[
  {
    "path": ".classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"src\" output=\"target/classes\" path=\"src/main/java\">\n\t\t<attributes>\n\t\t\t<attribute name=\"optional\" value=\"true\"/>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry excluding=\"**\" kind=\"src\" output=\"target/classes\" path=\"src/main/resources\">\n\t\t<attributes>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"src\" output=\"target/test-classes\" path=\"src/test/java\">\n\t\t<attributes>\n\t\t\t<attribute name=\"test\" value=\"true\"/>\n\t\t\t<attribute name=\"optional\" value=\"true\"/>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER\">\n\t\t<attributes>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t\t<attribute name=\"org.eclipse.jst.component.dependency\" value=\"/WEB-INF/lib\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v8.5\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8\">\n\t\t<attributes>\n\t\t\t<attribute name=\"maven.pomderived\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"output\" path=\"target/classes\"/>\n</classpath>\n"
  },
  {
    "path": ".gitattributes",
    "content": "\n*.js linguist-language=java\n*.css linguist-language=java\n*.html linguist-language=java\n"
  },
  {
    "path": ".project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>Movie</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.wst.common.project.facet.core.builder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.wst.validation.validationbuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.m2e.core.maven2Builder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>\n\t\t<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t\t<nature>org.eclipse.m2e.core.maven2Nature</nature>\n\t\t<nature>org.eclipse.wst.common.project.facet.core.nature</nature>\n\t\t<nature>org.eclipse.wst.jsdt.core.jsNature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": ".settings/.jsdtscope",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry excluding=\"**/bower_components/*|**/node_modules/*|**/*.min.js\" kind=\"src\" path=\"src/main/webapp\"/>\n\t<classpathentry kind=\"src\" path=\"target/m2e-wtp/web-resources\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.wst.jsdt.launching.JRE_CONTAINER\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.wst.jsdt.launching.WebProject\">\n\t\t<attributes>\n\t\t\t<attribute name=\"hide\" value=\"true\"/>\n\t\t</attributes>\n\t</classpathentry>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.wst.jsdt.launching.baseBrowserLibrary\"/>\n\t<classpathentry kind=\"output\" path=\"\"/>\n</classpath>\n"
  },
  {
    "path": ".settings/org.eclipse.jdt.core.prefs",
    "content": "eclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\norg.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8\norg.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve\norg.eclipse.jdt.core.compiler.compliance=1.8\norg.eclipse.jdt.core.compiler.debug.lineNumber=generate\norg.eclipse.jdt.core.compiler.debug.localVariable=generate\norg.eclipse.jdt.core.compiler.debug.sourceFile=generate\norg.eclipse.jdt.core.compiler.problem.assertIdentifier=error\norg.eclipse.jdt.core.compiler.problem.enumIdentifier=error\norg.eclipse.jdt.core.compiler.problem.forbiddenReference=warning\norg.eclipse.jdt.core.compiler.release=disabled\norg.eclipse.jdt.core.compiler.source=1.8\n"
  },
  {
    "path": ".settings/org.eclipse.m2e.core.prefs",
    "content": "activeProfiles=\neclipse.preferences.version=1\nresolveWorkspaceProjects=true\nversion=1\n"
  },
  {
    "path": ".settings/org.eclipse.wst.common.component",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><project-modules id=\"moduleCoreId\" project-version=\"1.5.0\">\n    <wb-module deploy-name=\"Movie\">\n        <wb-resource deploy-path=\"/\" source-path=\"/target/m2e-wtp/web-resources\"/>\n        <wb-resource deploy-path=\"/\" source-path=\"/src/main/webapp\" tag=\"defaultRootSource\"/>\n        <wb-resource deploy-path=\"/WEB-INF/classes\" source-path=\"/src/main/java\"/>\n        <wb-resource deploy-path=\"/WEB-INF/classes\" source-path=\"/src/main/resources\"/>\n        <property name=\"context-root\" value=\"Movie\"/>\n        <property name=\"java-output-path\" value=\"/Movie/target/classes\"/>\n    </wb-module>\n</project-modules>\n"
  },
  {
    "path": ".settings/org.eclipse.wst.common.project.facet.core.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<faceted-project>\n  <fixed facet=\"wst.jsdt.web\"/>\n  <installed facet=\"jst.web\" version=\"3.1\"/>\n  <installed facet=\"wst.jsdt.web\" version=\"1.0\"/>\n  <installed facet=\"java\" version=\"1.8\"/>\n</faceted-project>\n"
  },
  {
    "path": ".settings/org.eclipse.wst.jsdt.ui.superType.container",
    "content": "org.eclipse.wst.jsdt.launching.baseBrowserLibrary"
  },
  {
    "path": ".settings/org.eclipse.wst.jsdt.ui.superType.name",
    "content": "Window"
  },
  {
    "path": ".settings/org.eclipse.wst.validation.prefs",
    "content": "disabled=06target\neclipse.preferences.version=1\n"
  },
  {
    "path": "README.md",
    "content": "# 仿猫眼电影购票系统\n## 基于Spring+Spring MVC+Mybatis+Layui\n### 功能：\n* 前台：\n    * 登录、注册、注销\n    * 基本信息修改、修改头像、修改密码\n    * 按标签检索电影\n    * 根据电影选择场次\n    * 根据场次选择座位\n    * 购票\n    * 查看个人订单\n    * 申请退票\n    * 发布评论、修改评论、删除评论\n* 后台：\n    + 用户管理：增、删、改、查\n    + 电影管理：添加电影、修改和下架前台在映的电影\n    + 场次管理：\n        - 添加场次：选择影院、影院放映厅、电影、场次时间\n        - 场次下架\n        - 检索场次\n        - 查看上映、下架场次\n    + 评论管理：查看评论、根据用户检索评论、修改、删除\n    + 订单管理：\n        - 根据用户/订单编号检索订单\n        - 查看退票的订单\n        - 退票审核\n    + 票房统计：\n        - 统计系统电影类型的票房数据\n        - 统计系统电影票房排行前10的电影及票房<br>\n        \n### 前台预览：\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/index.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/电影.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/详情.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/选择影院.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/选择场次.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/选择位置.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/pay.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/success.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/个人信息.png)\n![qiantai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/订单.png)\n### 后台预览：\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/user.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/movie.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/movieadd.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/updatemovie.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/eva.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/schedule1.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/schedule2.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/scheduleadd.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/order1.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/order2.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/order3.png)\n![houtai](https://github.com/banbanzzz/Movie/blob/master/src/main/webapp/github/data.png)\n\n"
  },
  {
    "path": "movie.sql",
    "content": "/*\r\n Navicat Premium Data Transfer\r\n\r\n Source Server         : localhost_3306\r\n Source Server Type    : MySQL\r\n Source Server Version : 80012\r\n Source Host           : localhost:3306\r\n Source Schema         : movie\r\n\r\n Target Server Type    : MySQL\r\n Target Server Version : 80012\r\n File Encoding         : 65001\r\n\r\n Date: 06/08/2019 14:40:26\r\n*/\r\n\r\nSET NAMES utf8mb4;\r\nSET FOREIGN_KEY_CHECKS = 0;\r\n\r\n-- ----------------------------\r\n-- Table structure for cinema\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `cinema`;\r\nCREATE TABLE `cinema`  (\r\n  `cinema_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '影院编号',\r\n  `cinema_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '影院名称',\r\n  `cinema_address` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '影院地址',\r\n  PRIMARY KEY (`cinema_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of cinema\r\n-- ----------------------------\r\nINSERT INTO `cinema` VALUES (1, '中山奇幻电影院', '石岐区岐头新村龙凤街4号大信溢彩荟二期8楼');\r\nINSERT INTO `cinema` VALUES (2, '金逸影城中山石歧店', '石岐区大信南路2路大信新都汇5楼');\r\nINSERT INTO `cinema` VALUES (3, '博纳国际影城（中山IMAX店）', '古镇区同兴路98号利和广场购物中心四楼4009号');\r\nINSERT INTO `cinema` VALUES (4, 'UME影城（中山古镇店）', '古镇区中兴大道南一号花艺广场11层A区');\r\nINSERT INTO `cinema` VALUES (5, '中影100影城石歧店', '石岐区康华路15号恒基大厦3楼');\r\nINSERT INTO `cinema` VALUES (6, '橙天嘉禾影城（利和店）', '石岐区中山三路16号利和广场五层');\r\nINSERT INTO `cinema` VALUES (7, '珠影GCC影城（中山杜比全景声店）', '火炬高技术产业开发区火炬开发区港城路7号明珠广场二期');\r\nINSERT INTO `cinema` VALUES (8, '期遇·翼影城（东凤店）', '东凤镇东富路81号大顺时尚荟广场B座四楼（原君信大厦）');\r\nINSERT INTO `cinema` VALUES (9, '中山IM电影城（南朗壹加壹店）', '南朗镇岭南路62号新壹加壹4楼');\r\nINSERT INTO `cinema` VALUES (10, '艺达国际影城（小榄杜比全景声店）', '小榄镇新华中路118号大信新都汇118广场4楼');\r\nINSERT INTO `cinema` VALUES (11, '中影天乐电影城（海州汇海城店）', '古镇镇古镇海州市场汇海城北门电梯5楼（星海湾对面）');\r\nINSERT INTO `cinema` VALUES (12, '比高电影城（中山店）', '坦洲镇坦神北路118号皇爵假日广场4楼');\r\nINSERT INTO `cinema` VALUES (13, '大地影院（星宝时代店）', '沙溪镇乐群坎溪村（星宝路6号星宝时代广场）');\r\nINSERT INTO `cinema` VALUES (14, '中影星艺影城（南朗车站店）', '南朗镇南朗车站2楼');\r\nINSERT INTO `cinema` VALUES (15, '中影太阳城影院（张家边店）', '火炬高技术产业开发区东镇东一路23号太阳城购物中心4楼（近群英华庭）');\r\nINSERT INTO `cinema` VALUES (16, '五月花电影城（棕榈彩虹商业中心店）', '西区街道棕榈彩虹商业中心1座三楼（近新中医院）');\r\nINSERT INTO `cinema` VALUES (17, '高菲影城（中山万益广场店）', '板芙镇迎宾大道8号（万益广场店）');\r\nINSERT INTO `cinema` VALUES (18, '金逸影城（中山远洋城IMAX店）', '东区街道博爱六路28号远洋广场3幢大信新都汇4楼');\r\n\r\n-- ----------------------------\r\n-- Table structure for comment\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `comment`;\r\nCREATE TABLE `comment`  (\r\n  `comment_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '评论编号',\r\n  `user_id` bigint(10) NOT NULL COMMENT '所属用户编号',\r\n  `comment_content` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '评论内容',\r\n  `movie_id` bigint(10) NOT NULL COMMENT '所属电影编号',\r\n  `comment_time` datetime(0) NOT NULL COMMENT '评论时间',\r\n  PRIMARY KEY (`comment_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 58 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of comment\r\n-- ----------------------------\r\nINSERT INTO `comment` VALUES (3, 1, '不容错过', 3, '2019-07-18 15:15:22');\r\nINSERT INTO `comment` VALUES (4, 1, '车开电车侧壁如履平地，足踢卫星返回舱一脚拯救东京，我看柯南跟吴京此生必有一战吧', 4, '2019-07-13 11:15:01');\r\nINSERT INTO `comment` VALUES (5, 1, '看到最后一直在想真正的主角【皮球】怎么还不登场，结果果然没有让我失望。哦对，主役是皮球的话，二番就是安室的车了吧。', 5, '2019-07-13 11:15:14');\r\nINSERT INTO `comment` VALUES (7, 1, '东南亚电影院的观众们同时发出了杠铃般的笑声4536346', 7, '2019-07-24 02:37:36');\r\nINSERT INTO `comment` VALUES (8, 1, '谁要看你们检察院公安撕逼 我操 还我黑衣人组织', 8, '2019-07-13 11:15:51');\r\nINSERT INTO `comment` VALUES (10, 1, '还行，没吹得那么好，有点像强化娱乐性的海底版《黑豹》...故事线极其简单，打戏遍布扩成了143分钟的篇幅，对路人非常友好，不过这类过度炫目眼花缭乱的特效已经越看越麻木，什么海底《阿凡达》吹太过了，坐等《阿凡达2》的潘多拉海底世界吊打吧', 10, '2019-07-13 11:16:34');\r\nINSERT INTO `comment` VALUES (11, 2, '我是admin欢迎大家评论哦', 1, '2019-07-17 16:59:56');\r\nINSERT INTO `comment` VALUES (12, 2, '女王：维科，这是我大儿子，剩下的话不用我多说了吧，以后该怎么办，你自己招子放亮一点，好处不会少了你的。维科：晓得了。zz4124', 2, '2019-07-24 02:34:15');\r\nINSERT INTO `comment` VALUES (13, 2, '东有沉香劈山救母，西有海娃寻叉救母。绿色秋裤哲学变身，刺身放题海底大战。同母异父兄弟相残，弟妹大伯不伦之恋。温子仁携手徐锦江，亚裔之光拯救好莱坞！', 3, '2019-07-13 11:28:40');\r\nINSERT INTO `comment` VALUES (14, 2, '2.5 “我的恋人，就是这个国家啊！”———————好久没有听到这么烂的话了', 4, '2019-07-13 11:33:21');\r\nINSERT INTO `comment` VALUES (15, 2, '今年的柯南剧场版好无聊啊。。后面那段飙车简直夸张到无法理解，故事最后的反转也很让人无语，完全是多此一举，没有好的剧本就别拍了好吗，估计上映了也捞不到太多票房。ps:韩语版的柯南真的让人看得别扭不舒服..', 5, '2019-07-13 11:35:46');\r\nINSERT INTO `comment` VALUES (16, 2, '渔夫和灯塔守护多数是鳏夫，私下里经常养一些人鱼交欢。海洋远比陆地深远得多，人们赞美阳光下的海洋，却不知深夜降临海面上会冒出可怕的妖怪，海底也会藏着嘲笑人类的高级文明。所以！温子仁同样是一个借大热系列ip来讲自己故事的导演！', 6, '2019-07-13 11:36:08');\r\nINSERT INTO `comment` VALUES (17, 2, '海王可能要被微博营销号给奶死了。。。', 7, '2019-07-13 11:36:14');\r\nINSERT INTO `comment` VALUES (18, 2, '当陆地人为自己的文明沾沾自喜时，亚特兰蒂斯的服装设计已经领先我们几百年。', 8, '2019-07-13 11:36:41');\r\nINSERT INTO `comment` VALUES (19, 2, '温子仁就像一个从没拍过特效大片的暴发户。两星半，降降火。', 9, '2019-07-13 11:36:50');\r\nINSERT INTO `comment` VALUES (20, 2, '剧本，导演都有问题，很多片段都似曾相识，硬是凑了两个半小时真是辛苦了我的膀胱。然而剧情不够美工来凑，海底阿凡达，温子仁难担大任，DC要超越漫威还有很长的路要走。', 10, '2019-07-13 11:36:58');\r\nINSERT INTO `comment` VALUES (22, 3, '前面的小男孩突然问起诉是什么意思，我就在想这个故事小孩看得懂吗？动作场景依然需要帮忙按住牛顿的棺材板。', 4, '2019-07-13 11:37:43');\r\nINSERT INTO `comment` VALUES (23, 3, '7分。温子仁确实很厉害，原以为这该是系列中最无趣的一部，尤其各种水下戏份。结果，却难得拍的很好看。影片节奏感和大场面掌控上，确实很见功力。以及，温子仁还融入了很多他自己的趣味，也算很有趣的细节了。整体可看性还不错，就是略长了，海底的光怪陆离，看久了也会有些视觉疲劳。', 5, '2019-07-13 11:38:06');\r\nINSERT INTO `comment` VALUES (24, 3, '渔夫和灯塔守护多数是鳏夫，私下里经常养一些人鱼交欢。海洋远比陆地深远得多，人们赞美阳光下的海洋，却不知深夜降临海面上会冒出可怕的妖怪，海底也会藏着嘲笑人类的高级文明。所以！温子仁同样是一个借大热系列ip来讲自己故事的导演！', 3, '2019-07-13 11:38:35');\r\nINSERT INTO `comment` VALUES (25, 3, '故事老套了一点 但是昨晚我的主要任务是努力让自己不要在影院里发大水…Jason太尼玛适合这个角色了，就算他能轻而易举的把我操坏我也心甘情愿地承受这份痛苦', 9, '2019-07-13 11:39:10');\r\nINSERT INTO `comment` VALUES (26, 4, '飞机里的那一段是纪念，也是传承。钢铁侠说过，我们做的一切其实并不重要，重要的是我们选择给后代留下什么。而蜘蛛侠是托尼留给我们最好的遗产。', 10, '2019-07-13 11:39:30');\r\nINSERT INTO `comment` VALUES (27, 4, '多年以后，面对敌人，蜘蛛侠彼得·帕克将会回想起，托尼·斯塔克带他见识超级英雄们的那个遥远的下午。 两个彩蛋比正片有意思', 7, '2019-07-13 11:39:41');\r\nINSERT INTO `comment` VALUES (28, 4, '轻轻松松、啪啪砰砰，这样的超级英雄电影不挺好？温子仁真DC良心大管家——从头到尾堆特效，经费才烧1.6亿！欣赏不来海王徐锦江，51岁的妮可真的美炸了~~~~~', 6, '2019-07-13 11:39:57');\r\nINSERT INTO `comment` VALUES (29, 4, '天空属于卢卡斯 陆地属于杰克逊 海洋属于温子仁！！！', 2, '2019-07-13 11:40:13');\r\nINSERT INTO `comment` VALUES (30, 4, '特效和场景都非常不错，但是剧情和主角都非常不真实，唯一的真实人类就是那个收到新衣服以后改颜色镶铆钉的生命力很旺盛的青蛙反派。', 8, '2019-07-13 11:40:20');\r\nINSERT INTO `comment` VALUES (32, 5, '3.5；失落的亚特兰蒂斯之国，古远传说提供与一般超英片迥异的丰富背景，DC另辟蹊径，开启美妙神秘的水下世界，星站兵密集，温子仁不负众望且适时塞私货，海沟一战jump scare其乐无穷。视效惊人，音效震人，抛却鸡汤亲情，大场面调度甚是过瘾。妮可基德曼真·女神，形象太契合。', 2, '2019-07-13 11:41:14');\r\nINSERT INTO `comment` VALUES (33, 5, '我宣布！2018就是骨科文艺复兴之年！！！', 9, '2019-07-13 11:41:29');\r\nINSERT INTO `comment` VALUES (38, 2, '毒液好丑啊', 1, '2019-07-21 06:40:43');\r\nINSERT INTO `comment` VALUES (39, 4, '哇，这个毒液真的丑，但是女主真的好看！', 1, '2019-07-21 08:59:44');\r\nINSERT INTO `comment` VALUES (40, 6, '以为是R级片，结果是儿童片。汤老湿毫无邪气只有痞气，把一个反派英雄演得正气凛然到闷，而且毒液跟《寄生兽》一样竟然养着养着就变宠物了77', 1, '2019-07-21 09:04:27');\r\nINSERT INTO `comment` VALUES (41, 5, '无名之辈@@', 3, '2019-07-21 09:05:03');\r\nINSERT INTO `comment` VALUES (42, 5, '你好之华', 5, '2019-07-21 09:05:46');\r\nINSERT INTO `comment` VALUES (43, 6, '你的眼睛像火蜥蜴是我笨拙的情话，疯子离开懦夫是她最凶的咒骂，交换亲人让我的愧疚在博格特前显形，歃血为盟使我的爱在厄里斯镜里再现。点金石可以长生，纳吉尼终会成兽，爱心咒语不能保证天长地久，万咒皆终无法阻止核爆之灾。听说魔法世界也有很多爱恨与无奈，麻瓜世界里今年我的入学信还是被寄丢。', 2, '2019-07-21 09:06:34');\r\nINSERT INTO `comment` VALUES (44, 6, '活人办了葬礼，死人偏剩一口气。手机那头她是暗夜里绽放的花，天台边缘她是绝路尽头的桥。两个抢手机模型的憨皮，却无比清醒地看到对方的痴，何惧陷阱，哪管嫌疑。有的人是还没剥开的蛋壳，有的人是胸口夹带的铁板，有的人是虚张声势的水枪，有的人是无法愈合的伤口。几分痴憨皆是勇，几句咒骂都是爱。', 3, '2019-07-21 09:07:47');\r\nINSERT INTO `comment` VALUES (45, 3, '毒液好恶心，快看吐了。', 1, '2019-07-21 09:08:33');\r\nINSERT INTO `comment` VALUES (46, 6, '在岩井俊二的作品里算不上好，但也不差。里面的“时空信息传递”、“替身与错位”，看似是《情书》的反面，实则挖掘的是家庭代际的空间，引出稍显过满的群戏——每个角色都有互文关系。演员方面重点夸下金马提名的张子枫，没想到她竟是戏眼，两次落泪都是因为她。', 5, '2019-07-21 09:08:54');\r\nINSERT INTO `comment` VALUES (47, 3, '允儿来了zz', 1, '2019-07-21 09:09:21');\r\nINSERT INTO `comment` VALUES (48, 6, '顶顶顶', 4, '2019-07-21 09:09:23');\r\nINSERT INTO `comment` VALUES (49, 6, '别想着拍给年轻人看，拍给人看行不行。', 15, '2019-07-21 09:10:12');\r\nINSERT INTO `comment` VALUES (50, 6, '古天乐又缺钱建学校了', 16, '2019-07-21 09:10:38');\r\nINSERT INTO `comment` VALUES (51, 6, '以为玩三就完结甚至不敢期待怕失望，然而完全是惊喜。新元素加入很出彩，Woody找到归属，我的玩具系列完美结局。', 17, '2019-07-21 09:11:04');\r\nINSERT INTO `comment` VALUES (52, 6, '有点泰国惊悚片的味道了，说实话我好几次被吓的冷汗都出来了；虽然有一些场景还是感觉逻辑不通，但至少画面和节奏不渣。本来我都不知道这部电影，但是我对象说要看，那就看了这部，现在的问题是，他不在家的时候我怎么办？', 18, '2019-07-21 09:11:39');\r\nINSERT INTO `comment` VALUES (53, 6, '一个悲伤的故事：太阳都要毁灭，地球都要流浪了，我国的校服还是这么丑......', 20, '2019-07-21 09:12:06');\r\nINSERT INTO `comment` VALUES (54, 6, '不拍妓女三部曲的陈果就不是陈果了。电影拍得跟开玩笑一样。就像故事的走向，演员的演法，都带着些玩世不恭。而这不是诙谐是轻佻。观众并不想看你们在大银幕开玩笑。', 21, '2019-07-21 09:12:31');\r\nINSERT INTO `comment` VALUES (55, 3, '我的青春也全都是你呀', 26, '2019-07-21 09:19:26');\r\nINSERT INTO `comment` VALUES (56, 1, '观后影片：111', 1, '2019-07-22 11:15:03');\r\nINSERT INTO `comment` VALUES (57, 1, '神奇个锤子', 2, '2019-07-22 11:46:01');\r\n\r\n-- ----------------------------\r\n-- Table structure for hall\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `hall`;\r\nCREATE TABLE `hall`  (\r\n  `hall_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '放映厅编号',\r\n  `hall_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '放映厅名称',\r\n  `hall_capacity` int(10) NOT NULL DEFAULT 144 COMMENT '放映厅容量 默认为144  12 x 12 ',\r\n  `cinema_id` bigint(10) NOT NULL COMMENT '所属影院编号',\r\n  PRIMARY KEY (`hall_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 52 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of hall\r\n-- ----------------------------\r\nINSERT INTO `hall` VALUES (1, '1号厅', 144, 1);\r\nINSERT INTO `hall` VALUES (2, '1号厅', 144, 2);\r\nINSERT INTO `hall` VALUES (3, '1号厅', 144, 3);\r\nINSERT INTO `hall` VALUES (4, '1号厅', 144, 4);\r\nINSERT INTO `hall` VALUES (5, '1号厅', 144, 5);\r\nINSERT INTO `hall` VALUES (6, '1号厅', 144, 6);\r\nINSERT INTO `hall` VALUES (7, '2号厅', 144, 1);\r\nINSERT INTO `hall` VALUES (8, '2号厅', 144, 2);\r\nINSERT INTO `hall` VALUES (9, '2号厅', 144, 3);\r\nINSERT INTO `hall` VALUES (10, '2号厅', 144, 4);\r\nINSERT INTO `hall` VALUES (11, '2号厅', 144, 5);\r\nINSERT INTO `hall` VALUES (12, '2号厅', 144, 6);\r\nINSERT INTO `hall` VALUES (13, '3号厅', 144, 1);\r\nINSERT INTO `hall` VALUES (14, '1号厅', 144, 7);\r\nINSERT INTO `hall` VALUES (15, '1号厅', 144, 8);\r\nINSERT INTO `hall` VALUES (16, '1号厅', 144, 9);\r\nINSERT INTO `hall` VALUES (17, '1号厅', 144, 10);\r\nINSERT INTO `hall` VALUES (18, '1号厅', 144, 11);\r\nINSERT INTO `hall` VALUES (19, '1号厅', 144, 12);\r\nINSERT INTO `hall` VALUES (20, '1号厅', 144, 13);\r\nINSERT INTO `hall` VALUES (21, '1号厅', 144, 14);\r\nINSERT INTO `hall` VALUES (22, '1号厅', 144, 15);\r\nINSERT INTO `hall` VALUES (23, '1号厅', 144, 16);\r\nINSERT INTO `hall` VALUES (24, '1号厅', 144, 17);\r\nINSERT INTO `hall` VALUES (25, '1号厅', 144, 18);\r\nINSERT INTO `hall` VALUES (26, '2号厅', 144, 7);\r\nINSERT INTO `hall` VALUES (27, '2号厅', 144, 8);\r\nINSERT INTO `hall` VALUES (28, '2号厅', 144, 9);\r\nINSERT INTO `hall` VALUES (29, '2号厅', 144, 10);\r\nINSERT INTO `hall` VALUES (30, '2号厅', 144, 11);\r\nINSERT INTO `hall` VALUES (31, '2号厅', 144, 12);\r\nINSERT INTO `hall` VALUES (32, '2号厅', 144, 13);\r\nINSERT INTO `hall` VALUES (33, '2号厅', 144, 14);\r\nINSERT INTO `hall` VALUES (34, '2号厅', 144, 15);\r\nINSERT INTO `hall` VALUES (35, '2号厅', 144, 16);\r\nINSERT INTO `hall` VALUES (36, '2号厅', 144, 17);\r\nINSERT INTO `hall` VALUES (37, '2号厅', 144, 18);\r\nINSERT INTO `hall` VALUES (38, '3号厅', 144, 3);\r\nINSERT INTO `hall` VALUES (39, '3号厅', 144, 5);\r\nINSERT INTO `hall` VALUES (40, '3号厅', 144, 7);\r\nINSERT INTO `hall` VALUES (41, '3号厅', 144, 10);\r\nINSERT INTO `hall` VALUES (42, '3号厅', 144, 11);\r\nINSERT INTO `hall` VALUES (43, '3号厅', 144, 15);\r\nINSERT INTO `hall` VALUES (44, '3号厅', 144, 18);\r\nINSERT INTO `hall` VALUES (45, 'IMAX厅', 144, 1);\r\nINSERT INTO `hall` VALUES (46, 'IMAX厅', 144, 3);\r\nINSERT INTO `hall` VALUES (47, 'IMAX厅', 144, 8);\r\nINSERT INTO `hall` VALUES (48, 'IMAX厅', 144, 12);\r\nINSERT INTO `hall` VALUES (49, 'IMAX厅', 144, 14);\r\nINSERT INTO `hall` VALUES (50, 'IMAX厅', 144, 16);\r\nINSERT INTO `hall` VALUES (51, 'IMAX厅', 144, 17);\r\n\r\n-- ----------------------------\r\n-- Table structure for movie\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `movie`;\r\nCREATE TABLE `movie`  (\r\n  `movie_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '电影编号',\r\n  `movie_cn_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '电影名称（中文）',\r\n  `movie_fg_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '电影名称（外语）',\r\n  `movie_actor` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影演职人员',\r\n  `movie_director` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影导演',\r\n  `movie_detail` varchar(350) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影详情',\r\n  `movie_duration` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影时长',\r\n  `movie_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影类型',\r\n  `movie_score` float(10, 1) NULL DEFAULT 0.0 COMMENT '电影评分 默认为0',\r\n  `movie_boxOffice` float(10, 4) NULL DEFAULT 0.0000 COMMENT '电影票房 默认为0',\r\n  `movie_commentCount` bigint(10) NULL DEFAULT 0 COMMENT '电影参评人数 默认为0',\r\n  `movie_releaseDate` date NOT NULL COMMENT '电影上映时间',\r\n  `movie_country` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影制片地区',\r\n  `movie_picture` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影海报',\r\n  `movie_state` int(3) NOT NULL DEFAULT 1 COMMENT '电影状态 默认为1  1：在线 0：下架',\r\n  PRIMARY KEY (`movie_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of movie\r\n-- ----------------------------\r\nINSERT INTO `movie` VALUES (1, '毒液：致命守护者', 'Venom', '汤姆·哈迪:埃迪·布洛克/毒液,米歇尔·威廉姆斯:安妮·韦英', '鲁本·弗雷斯彻', '身为记者的埃迪·布洛克（汤姆·哈迪饰）在调查生命基金会老板卡尔顿·德雷克（里兹·阿迈德饰）的过程中，事业遭受重创，与未婚妻安妮·韦英（米歇尔·威廉姆斯饰）的关系岌岌可危，并意外被外星共生体控制，他历经挣扎对抗，最终成为拥有强大超能力，无人可挡的“毒液“', '107分钟', '动作，科幻', 7.2, 1.0209, 7, '2019-06-24', '美国', '../upload/movies/c91fef2f9e2b4d5295cd12e9abf507d9.jpg', 1);\r\nINSERT INTO `movie` VALUES (2, '神奇动物：格林德沃之罪', 'Fantastic Beasts: The Crimes of Grindelwald', '埃迪·雷德梅恩:纽特·斯卡曼德,凯瑟琳·沃特斯顿:蒂娜‧戈德斯坦,约翰尼·德普:盖勒·格林德沃', '大卫·叶茨', '在《神奇动物在那里》第一部的结尾，纽特·斯卡曼德（埃迪·雷德梅恩 饰）协助美国魔法国会，将强大的黑巫师盖勒特·格林德沃（约翰尼·德普 饰）抓捕归案。但格林德沃不久便兑现狂言成功越狱，并开始纠集信徒，着手实现他们的邪恶目的：让纯血统的巫师成为统治阶层，镇压一切非魔法生物。为挫败格林德沃的阴谋，阿不思·邓布利多（裘德·洛 饰）向昔日的学生纽特·斯卡曼德寻求帮助。纽特欣然允诺，却没有意识到，他将踏上的会是一段充满艰险的未来征途。此时的魔法世界面临空前的分裂乱局，阶层鸿沟日益加深，爱与忠诚备受考验，至亲好友也可能反目成仇……', '134分钟', '奇幻，冒险', 7.7, 1.0339, 5, '2019-06-25', '美国', '../upload/movies/Fantastic Beasts.jpg', 1);\r\nINSERT INTO `movie` VALUES (3, '无名之辈', 'A Cool Fish', '陈建斌:马先勇,任素汐:马嘉旗,潘斌龙:李海根', '饶晓志', '在一座山间小城中，一对低配劫匪、一个落魄的泼皮保安、一个身体残疾却性格彪悍的残毒舌女以及一系列生活在社会不同轨迹上的小人物，在一个貌似平常的日子里，因为一把丢失的老枪和一桩当天发生在城中的乌龙劫案，从而被阴差阳错地拧到一起，发生的一幕幕令人啼笑皆非的荒诞喜剧', '108分钟', '荒诞，喜剧', 9.2, 1.0315, 5, '2019-07-05', '中国大陆', '../upload/movies/A Cool Fish.jpg', 1);\r\nINSERT INTO `movie` VALUES (4, '名侦探柯南：零的执行人', '名探偵コナン ゼロの執行人', '高山南:江户川柯南,山崎和佳奈:毛利兰,林原惠美:灰原哀', '立川让', '5月1日，东京湾边的新建筑“海洋边缘”将举办首脑云集的东京峰会。然而，峰会开办前一周，会场发生超大规模的爆炸事件，并出现了安室透的身影。疑似恐怖袭击的事件引起了警察部门的严肃调查。在警察局大型搜查会议上，公安部门提交证物，却发现疑犯指纹与毛利小五郎（小山力也 配音）指纹吻合。作为律师的妃英理努力收集证据证明丈夫的无辜，却无力阻止毛利小五郎被收监。看到毛利兰（山崎和佳奈 配音）绝望哭泣的样子，柯南（高山南 配音）决定调查事件真相，还毛利小五郎清白。另一方面，少年侦探团的孩子们正紧密关注着无人探测器“天鹅”的回航任务。行踪诡异的安室透、惨遭陷害的毛利小五郎、错综复杂的警察部门、即将着陆的无人探测器；随着“机密任务”进入倒计时，关乎整个东京的可怕计划拉开帷幕…', '111分钟', '悬疑，冒险，动画', 8.5, 1.0256, 4, '2019-07-13', '日本', '../upload/movies/名探偵.jpg', 1);\r\nINSERT INTO `movie` VALUES (5, '你好，之华', 'Last Letter', '周迅:袁之华,秦昊:尹川,杜江:周文涛', '岩井俊二', '有人慌张得见面，有人简单地告别。姐姐袁之南离世的那个清晨，只匆匆留下一封信和一张同学会邀请函。妹妹之华(周迅 饰)代替姐姐参加，却意外遇见年少时的倾慕对象尹川（秦昊 饰）。往日的记忆在苏醒，但再次相见，已物是人非', '114分钟', '爱情', 7.9, 1.0108, 5, '2019-07-20', '中国大陆、日本', '../upload/movies/Last Letter.jpg', 1);\r\nINSERT INTO `movie` VALUES (6, '恐龙王', 'DINO KING', '吕佩玉:钢妈,王衡:斑大师,孙晔:八百度', '施雅雅', '陆地霸主特暴龙“斑大师”和自己的小儿子“小疙瘩”生活在一起。“小疙瘩”自幼失去了母亲，生性懦弱，严厉的“斑大师”虽然心底十分疼爱自己的孩子，但是急于让“小疙瘩”成长为新的陆地霸主，常常忍不住责骂“小疙瘩”，父子俩虽然相依为命，却始终有一些隔阂。 一天“小疙瘩”被几只邪恶的恐爪龙抓走，“斑大师”踏上漫漫的寻子之路，路途中他结识了有高度近视眼的美甲龙“八百度”，两人穿过“巨蝎峡”、走出“长颈龙绿洲”、踏上火山峡谷，经历了重重难关。而身处险境的“小疙瘩”也结识了一些新的朋友，并且开始和邪恶的恐爪龙斗智斗勇。最终父子两人终于相见，但是却不得不一起面对一个更加凶恶的史前怪物……', '95分钟', '喜剧，动画，冒险', 8.9, 1.0000, 2, '2018-12-10', '中国大陆', '../upload/movies/DINO KING.jpg', 0);\r\nINSERT INTO `movie` VALUES (7, '冰封侠：时空行者', 'Bing Feng Xia II', '甄子丹:贺英,黄圣依:小美,王宝强:萨獒', '叶伟民', '明朝大将军贺英（甄子丹 饰）利用时空金球终于重返明朝，与锦衣卫兄弟萨獒（王宝强 饰）获悉了倭寇和朝廷奸党之间足以倾覆皇权的密谋，绵延400年的惊天危机一触即发。贺英也在红颜知己小美（黄圣依 饰）的帮助下开始了抗倭锄奸和保护族人的战斗', '87分钟', '剧情，动作', 4.1, 1.0000, 3, '2018-09-02', '中国大陆', '../upload/movies/Bing Feng Xia II.jpg', 0);\r\nINSERT INTO `movie` VALUES (8, '梦境之源', 'Source of Dreams', '陈志朋:徐朗,颜丹晨:李雪,方中信:梁文道', '柳珂', '货车司机李昂由于童年时代内向懦弱，颓废度日，频频做噩梦，严重影响了正常的生活，并因此不得不接受心理医生曹井润的催眠治疗，却在梦境中意外卷入一场凶杀案。睿智破案的警探成为凶手，而真正的幕后黑手仍在逍遥法外……', '90分钟', '悬疑，推理', 5.9, 1.0000, 3, '2018-11-16', '中国大陆', '../upload/movies/Source of Dreams.jpg', 0);\r\nINSERT INTO `movie` VALUES (9, '摘金奇缘', 'Crazy Rich Asians', '吴恬敏:朱瑞秋,亨利·戈尔丁:杨尼克,杨紫琼:杨爱莉', '朱浩伟', '新加坡富二代王子杨尼克（亨利·戈尔丁饰）自豪地带着美丽大方、学识傲人的女友朱瑞秋（吴恬敏饰）回家见亲友。而这个巨富大家族对朱瑞秋的态度，与她的想像相差十万八千里远，朱瑞秋一开始以为只是跟深爱的男人轻松浪漫地度假，不料却面对排山倒海般的压力，她必须坚强应对一群有心机的情敌和反对者，但更难搞的竟然是她的准婆婆杨爱莉（杨紫琼饰），因为埃莉诺认为朱瑞秋这个现代美国女孩永远都高攀不上她们家', '120分钟', '喜剧，爱情', 6.1, 1.0000, 3, '2018-11-30', '美国', '../upload/movies/Crazy Rich Asians.jpg', 0);\r\nINSERT INTO `movie` VALUES (10, '海王', 'Aquaman', '杰森·莫玛:海王/亚瑟·库瑞,艾梅柏·希尔德:海后/湄拉,威廉·达福:努迪斯·维科', '温子仁', '在一场狂风暴雨的海边灯塔看守人汤姆·库瑞（特穆拉·莫里森饰）救了受伤的亚特兰蒂斯女王亚特兰娜（妮可·基德曼饰）之后，他们相爱了，生下了拥有半人类、半亚特兰蒂斯人的血统亚瑟·库瑞（杰森·莫玛饰）。为了救自己的爱人和儿子亚特兰娜选择了离开。\\r\\n几年之后，亚特兰娜被迫回到海底国家缔结政治婚姻，生下儿子奥姆（帕特里克·威尔森饰）。奥姆长大后当上国王对陆地人类充满憎恨，开始吞并海底中发展中的国家的兵力，一举消灭陆地人。奥姆的未婚妻海底王国泽贝尔公主湄拉（艾梅柏·希尔德饰）打算阻止这场战争，她到陆地找回亚瑟，让他以亚特兰娜女王长子身份回亚特兰蒂斯把王位争回来，而且湄拉要协助亚瑟找回能统治大海的失落的三叉戟', '143分钟', '动作，科幻', 7.6, 1.0000, 3, '2018-12-07', '美国、澳大利亚', '../upload/movies/Aquaman.jpg', 0);\r\nINSERT INTO `movie` VALUES (15, '素人特工', 'The Rookies', '王大陆:赵风,张榕容:淼淼', '袁锦麟', '极限运动达人赵风（王大陆 饰），误打误撞闯入了一场国际犯罪交易，不得不跟随国际特工（米拉·乔沃维奇 饰）一起前往布达佩斯。在这里他与废柴刑警淼淼（张榕容 饰）、民间科学家丁山（许魏洲 饰）与待业医生LV（刘美彤 饰）组成一支素人特工小队。这四个特工小白和高级国际特攻米拉一起，与恐怖分子开启了一场又惊又喜的斗争。', '113分钟', '喜剧,动作,冒险', 7.2, 1.0000, 1, '2019-07-12', '中国大陆', '../upload/movies/素人特工.jpg', 1);\r\nINSERT INTO `movie` VALUES (16, '追龙Ⅱ', 'Chasing the Dragon Ⅱ', '梁家辉:龙志强,古天乐:何天', '王晶', '悍匪龙志强（梁家辉 饰），在香港回归前，趁香港英政府不作为，而屡犯巨案，先后绑架富豪利家及雷家之长子，勒索超过二十亿元，事主怕被报复, 交赎款后都不敢报警。中国公安部极为关注，与香港警方合力，派香港警员何天（古天乐 饰）卧底潜入龙志强犯罪团伙，发现他正策划绑架澳门富豪贺不凡，最终陆港警察合力勇擒龙志强，救出贺不凡', '103分钟', '犯罪,剧情,动作', 7.9, 1.0120, 1, '2019-06-06', '中国大陆、中国香港', '../upload/movies/追龙Ⅱ.jpg', 1);\r\nINSERT INTO `movie` VALUES (17, '玩具总动员4', 'Toy Story 4', '汤姆·汉克斯:胡迪,蒂姆·艾伦:巴斯光年', '乔什·库雷', '当邦妮将所有玩具带上房车家庭旅行时，胡迪（汤姆·汉克斯 配音）与伙伴们将共同踏上全新的冒险之旅，领略房间外面的世界有多广阔，甚至偶遇老朋友牧羊女（安妮·波茨 配音）。在多年的独自闯荡中，牧羊女已经变得热爱冒险，不再只是一个精致的洋娃娃。正当胡迪和牧羊女发现彼此对玩具的使命的意义大相径庭时，他们很快意识到更大的威胁即将到来。', '100分钟', '喜剧,动画,奇幻', 9.1, 1.0000, 1, '2019-06-21', '美国', '../upload/movies/玩具总动员4.jpg', 1);\r\nINSERT INTO `movie` VALUES (18, '碟仙', 'Mortal Ouija', '黄奕:梦瑶,范逸臣:项天', '廉涛', '以网络直播为业的单亲妈妈梦瑶（黄奕 饰）带着上幼儿园的女儿雯雯住进了一栋便宜的学区房，然而，屋里的诡异氛围，与不时散发的奇怪恶臭，令梦瑶感到不安。某夜，雯雯竟然在梦游中，玩了前租客遗留的“碟仙”游戏。传说只要玩过的人，七日内必会被碟仙夺命！紧接着，屋内接连发生令人毛骨悚然的怪事。七日大限将至，眼看爱女危在旦夕，为了解开碟仙诅咒，夺回女儿，绝望的妈妈不惜做出了惊人的举动……', '83分钟', '恐怖,惊悚', 7.9, 1.0056, 1, '2019-06-21', '中国大陆', '../upload/movies/碟仙.jpg', 1);\r\nINSERT INTO `movie` VALUES (19, '扫毒', 'The White Storm', '古天乐:苏建秋,刘青云:马昊天', '陈木胜', '以马昊天（刘青云 饰）为首的毒品调查科，与手下张子伟（张家辉 饰）和卧底苏建秋（古天乐 饰）在执行一次跨国的大型扫毒行动中，被毒犯巨头八面佛（卢海鹏 饰）暗中揭发反埋伏，最终全军覆没。面对生死关头，三位主角为求活存，被迫命运扭转，展开一场残酷的人生战役。', '134分钟', '剧情,犯罪', 8.9, 1.0000, 0, '2018-11-21', '中国大陆、中国香港', '../upload/movies/扫毒.jpg', 0);\r\nINSERT INTO `movie` VALUES (20, '流浪地球', 'The Wandering Earth', '吴京:刘培强,屈楚萧:刘启', '郭帆', '近未来，科学家们发现太阳急速衰老膨胀，短时间内包括地球在内的整个太阳系都将被太阳所吞没。为了自救，人类提出一个名为“流浪地球”的大胆计划，即倾全球之力在地球表面建造上万座发动机和转向发动机，推动地球离开太阳系，用2500年的时间奔往另外一个栖息之地。中国航天员刘培强在儿子刘启四岁那年前往国际空间站，和国际同侪肩负起领航者的重任。转眼刘启长大，他带着妹妹朵朵偷偷跑到地表，偷开外公韩子昂的运输车，结果不仅遭到逮捕，还遭遇了全球发动机停摆的事件。为了修好发动机，阻止地球坠入木星，全球开始展开饱和式营救，连刘启他们的车也被强征加入。在与时间赛跑的过程中，无数的人前仆后继，奋不顾身，只为延续百代子孙生存的希望…… 本片根据刘慈欣的同名小说改编。', '125分钟', '剧情,冒险,科幻', 9.2, 1.0000, 1, '2019-07-05', '中国大陆、中国香港', '../upload/movies/流浪地球.jpg', 1);\r\nINSERT INTO `movie` VALUES (21, '九龙不败', 'The Invincible Dragon', '张晋:九龙', '陈果', '警探九龙（张晋 饰），查案方式奇异狠辣却屡建奇功，是叱咤香港警界的精英干探, 但他处事独断爆裂，又被警队视为“偏执狂人”。九龙奉命调查一桩妙龄女警连环被凶杀 案，用尽手段后不仅毫无线索, 他的警花未婚妻方宁（邓丽欣 饰）竟然也在这场抓捕行动中意外失踪。在爱与痛的边缘挣扎的九龙，突然发现女警连环遇害只是第一步，凶手还有着更加血腥的阴谋，自己和未婚妻竟然也被算计其中。此时澳门再度发生女警被杀案，这次的作案手法更加令人发指，但凶手好像故意留下了线索，是危险陷阱还是复仇曙光？九龙义无反顾出发，在好友王梦奇（刘心悠 饰）及国际拳王冼力山（安德森·席尔瓦 饰）的协助下, 与澳门警司曹志德（郑嘉颖 饰）联手展开调查。魔高一丈，道高几何！血债血偿之前，就算流干最后一滴血，也要誓不罢休。', '100分钟', '剧情,动作,犯罪', 5.7, 1.0000, 1, '2019-07-02', '中国大陆、中国香港', '../upload/movies/九龙不败.jpg', 1);\r\nINSERT INTO `movie` VALUES (22, '阿丽塔：战斗天使', 'Alita: Battle Angel', '罗莎·萨拉查:阿丽塔,克里斯托弗·沃尔兹:戴森·艾德博士', '罗伯特·罗德里格兹', '未来26世纪，科技发展，人类与机械改造人共存，弱肉强食是钢铁城唯一的生存法则。依德（克里斯托夫·沃尔兹 饰）是钢铁城著名的改造人医生，他在垃圾场发现了一个半机械少女残躯，依德医生将其拯救后为她取名阿丽塔（罗莎·萨拉扎尔 饰）。阿丽塔虽然重获生命却失去了记忆，如一个新生儿一样对这个世界充满新鲜感。在依德医生与好友雨果（基恩·约翰逊 饰）的帮助下，她逐步适应着新生活和街头险恶。一次偶然的机会，阿丽塔发现自己竟有着惊人的战斗天赋。 一次次猎杀激发着她的觉醒，阿丽塔逐渐明白自己注定为战斗而生，为正义而战。一场揭开自己身世之谜，并打破宇宙旧秩序的史诗级冒险之旅就这样展开。', '122分钟', '动作,冒险,科幻', 9.0, 1.0000, 0, '2019-07-11', '美国', '../upload/movies/阿丽塔：战斗天使.jpg', 1);\r\nINSERT INTO `movie` VALUES (23, 'X战警：黑凤凰', 'X-Men: Dark Phoenix', '苏菲·特纳:琴·格雷/黑凤凰,詹姆斯·麦卡沃伊:查尔斯·泽维尔/X教授', '西蒙·金伯格', '在一次危及生命的太空营救行动中，琴·葛蕾（苏菲·特纳 饰）被神秘的宇宙力量击中，成为最强大的变种人。此后琴不仅要设法掌控日益增长、极不稳定的力量，更要与自己内心的恶魔抗争，她的失控让整个X战警大家庭分崩离析，也让整个星球陷入毁灭的威胁之中……', '114分钟', '动作,冒险,科幻', 7.8, 1.0000, 0, '2019-06-06', '美国', '../upload/movies/X战警：黑凤凰.jpg', 1);\r\nINSERT INTO `movie` VALUES (24, '疯狂的外星人', 'Crazy Alien', '黄渤:耿浩,沈腾:大飞,马修·莫里森:扎克,汤姆·派福瑞:约翰', '宁浩', '耿浩（黄渤 饰）与一心想发大财的好兄弟大飞（沈腾 饰），经营着各自惨淡的“事业”，然而“天外来客”（徐峥 饰）的意外降临，打破了二人平静又拮据的生活。神秘的西方力量也派出“哼哈二将”在全球搜查外星人行踪。啼笑皆非的跨物种对决，别开生面的“星战”，在中国某海边城市激情上演。', '116分钟', '剧情,喜剧,科幻', 8.5, 1.0000, 0, '2019-07-10', '中国大陆、美国', '../upload/movies/疯狂的外星人.jpg', 1);\r\nINSERT INTO `movie` VALUES (25, '八子', 'ADVANCE WAVE UPON WAVE', '刘端端:满崽,邵兵:大牛', '高希希', '上世纪30年代的赣南地区，在这个被称为中国革命“红色摇篮”的地方，曾经有这样一位母亲，她将八个儿子先后送入红军，奔赴战场前线。但战火无情，兄弟中的六人陆续牺牲，只剩下大哥杨大牛和最小的孩子满崽。满崽找到了大牛的部队，成了哥哥麾下的普通一兵，经过一场场战役的淬炼，新兵满崽迅速成长为一个真正的战士。最后的战斗打响了，为了掩护大部队安全撤离，杨大牛带领弟弟满崽和全体战友浴血肉搏，直至弹尽粮绝…… 英雄的身前，是枪林弹雨的沙场，而在英雄的身后，家乡的村庄依然宁静安详，微风吹过金黄的稻浪簌簌作响，一位年迈的母亲正在村头的小路旁孤独的守望……', '121分钟', '战争,历史,动作', 8.4, 1.0118, 0, '2019-06-30', '中国大陆', '../upload/movies/bazi.jpg', 1);\r\nINSERT INTO `movie` VALUES (26, '我的青春都是你', 'Love The Way You Are', '宋威龙:方予可,宋芸桦:周林林,林妍柔:茹婷,黄俊捷:谢端西,金士杰:畜牧系老师', '周彤', '周林林（宋芸桦 饰）高考发挥超常进入东方大学，与同校理科状元方予可（宋威龙 饰）一同进入了最高学府。郎有情妾无意，方予可其实从幼儿园时期就心系周林林，人生若只如初见，儿时的初遇相见便立下了日久的暗恋情愫！但万人瞩目的帅哥方予可身边有天之骄女茹庭（林妍柔 饰），从小暗恋状元对周林林看不顺眼，周林林则对方予可身边的同为校园风云人物的小西学长（黄俊捷 饰）心存爱慕，修习大学恋爱秘籍，苦练恋爱通关技巧，十八般武艺七十二变法轮番上阵！四人之间情感纠葛，在校园里上演了一幕青春爱情喜剧！', '92分钟', '爱情,青春', 7.3, 1.0000, 1, '2019-06-21', '中国大陆、中国台湾', '../upload/movies/我的青春都是你.jpg', 1);\r\nINSERT INTO `movie` VALUES (27, '银河补习班', 'Looking up', '邓超:马皓文,白宇:成年马飞', '俞白眉', '浩瀚太空，航天员意外失联，生命最大的绝境中，他回忆起自己那个最了不起的爸爸。一对父子跨越漫长的时光，守护爱和亲情，故事充满了欢乐、温暖、泪水与奇观。', '147分钟', '剧情,家庭', 9.1, 1.0200, 0, '2019-07-18', '中国大陆', '../upload/movies/银河补习班.jpg', 1);\r\nINSERT INTO `movie` VALUES (28, '1', '2', '4:4,52:54235', '3', '5', '6', '7', 8.9, 0.0000, 0, '2019-07-02', '9', '../upload/movies/9a9351332a5149c895b57b4564dbe667.jpg', 1);\r\n\r\n-- ----------------------------\r\n-- Table structure for orderinfo\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `orderinfo`;\r\nCREATE TABLE `orderinfo`  (\r\n  `order_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单编号',\r\n  `user_id` bigint(10) NOT NULL COMMENT '所属用户编号',\r\n  `schedule_id` bigint(10) NOT NULL COMMENT '所属场次编号',\r\n  `order_position` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影票座位 （x排x座）',\r\n  `order_state` int(10) NOT NULL DEFAULT 1 COMMENT '订单状态 0:退票中 1:已支付 2:退票成功',\r\n  `order_price` int(10) NOT NULL COMMENT '订单价格',\r\n  `order_time` datetime(0) NOT NULL COMMENT '订单支付时间',\r\n  PRIMARY KEY (`order_id`) USING BTREE\r\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of orderinfo\r\n-- ----------------------------\r\nINSERT INTO `orderinfo` VALUES ('2019072100030210', 3, 25, '2排10座', 1, 38, '2019-07-21 07:01:36');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030306', 3, 310, '3排6座', 1, 40, '2019-07-21 14:44:34');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030307', 3, 26, '3排7座', 0, 40, '2019-07-21 07:07:09');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030409', 3, 26, '4排9座', 1, 40, '2019-07-21 07:14:37');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030508', 3, 310, '5排8座', 2, 40, '2019-07-21 14:44:35');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030603', 3, 310, '6排3座', 1, 40, '2019-07-21 14:44:35');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030606', 3, 310, '6排6座', 1, 40, '2019-07-21 14:44:35');\r\nINSERT INTO `orderinfo` VALUES ('2019072100040606', 4, 27, '6排6座', 1, 55, '2019-07-21 08:55:39');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050506', 5, 65, '5排6座', 2, 45, '2019-07-21 08:52:01');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050507', 5, 65, '5排7座', 0, 45, '2019-07-21 08:52:01');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050509', 5, 135, '5排9座', 1, 32, '2019-07-21 08:50:26');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050510', 5, 135, '5排10座', 1, 32, '2019-07-21 08:50:27');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060502', 6, 136, '5排2座', 1, 34, '2019-07-21 08:50:23');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060503', 6, 136, '5排3座', 1, 34, '2019-07-21 08:50:23');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060504', 6, 136, '5排4座', 1, 34, '2019-07-21 08:50:23');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060509', 6, 122, '5排9座', 1, 28, '2019-07-21 08:52:24');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060602', 6, 153, '6排2座', 0, 32, '2019-07-21 08:52:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060603', 6, 153, '6排3座', 1, 32, '2019-07-21 08:52:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060604', 6, 103, '6排4座', 0, 35, '2019-07-21 08:53:12');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060605', 6, 103, '6排5座', 1, 35, '2019-07-21 08:53:12');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060606', 6, 103, '6排6座', 1, 35, '2019-07-21 08:53:12');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060703', 6, 65, '7排3座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060704', 6, 65, '7排4座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060705', 6, 65, '7排5座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060706', 6, 65, '7排6座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060709', 6, 122, '7排9座', 0, 28, '2019-07-21 08:52:25');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060803', 6, 158, '8排3座', 0, 35, '2019-07-21 08:51:30');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060804', 6, 158, '8排4座', 0, 35, '2019-07-21 08:51:31');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010507', 1, 232, '5排7座', 1, 30, '2019-07-22 11:09:46');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010608', 1, 232, '6排8座', 1, 30, '2019-07-22 11:09:46');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010707', 1, 232, '7排7座', 1, 30, '2019-07-22 11:09:46');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010808', 1, 232, '8排8座', 1, 30, '2019-07-22 11:09:46');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010910', 1, 136, '9排10座', 0, 34, '2019-07-21 17:00:56');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010911', 1, 136, '9排11座', 1, 34, '2019-07-21 17:00:56');\r\nINSERT INTO `orderinfo` VALUES ('2019072200010912', 1, 160, '9排12座', 1, 35, '2019-07-22 11:46:52');\r\nINSERT INTO `orderinfo` VALUES ('2019072200020508', 2, 83, '5排8座', 0, 44, '2019-07-22 11:32:49');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040106', 4, 94, '1排6座', 1, 54, '2019-07-22 01:10:02');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040107', 4, 94, '1排7座', 1, 54, '2019-07-22 01:10:02');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040408', 4, 39, '4排8座', 1, 48, '2019-07-22 03:51:27');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040409', 4, 135, '4排9座', 1, 32, '2019-07-22 01:11:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040410', 4, 135, '4排10座', 1, 32, '2019-07-22 01:11:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040508', 4, 135, '5排8座', 1, 32, '2019-07-22 01:11:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040511', 4, 135, '5排11座', 1, 32, '2019-07-22 01:11:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040609', 4, 135, '6排9座', 1, 32, '2019-07-22 01:11:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072200040610', 4, 135, '6排10座', 1, 32, '2019-07-22 01:11:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072400010310', 1, 27, '3排10座', 1, 55, '2019-07-24 02:30:42');\r\nINSERT INTO `orderinfo` VALUES ('2019072400010311', 1, 27, '3排11座', 1, 55, '2019-07-24 02:30:43');\r\n\r\n-- ----------------------------\r\n-- Table structure for schedule\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `schedule`;\r\nCREATE TABLE `schedule`  (\r\n  `schedule_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '场次编号',\r\n  `hall_id` bigint(10) NOT NULL COMMENT '所属放映厅编号',\r\n  `movie_id` bigint(10) NOT NULL COMMENT '所属电影编号',\r\n  `schedule_startTime` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影放映时间',\r\n  `schedule_price` int(10) NOT NULL COMMENT '场次价格',\r\n  `schedule_remain` int(10) NOT NULL COMMENT '剩余座位数 默认=hall_capacity',\r\n  `schedule_state` int(10) NOT NULL DEFAULT 1 COMMENT '场次状态 默认1 1：上映中 0：下架',\r\n  PRIMARY KEY (`schedule_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 315 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of schedule\r\n-- ----------------------------\r\nINSERT INTO `schedule` VALUES (25, 1, 25, '2019-07-21 17:30', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (26, 7, 25, '2019-07-22 20:00', 40, 143, 1);\r\nINSERT INTO `schedule` VALUES (27, 7, 1, '2019-07-21 19:10', 55, 141, 0);\r\nINSERT INTO `schedule` VALUES (28, 8, 25, '2019-07-23 17:00', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (29, 1, 20, '2019-07-21 00:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (30, 13, 1, '2019-07-22 19:20', 55, 144, 1);\r\nINSERT INTO `schedule` VALUES (31, 7, 20, '2019-07-21 00:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (32, 13, 20, '2019-07-21 00:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (33, 1, 1, '2019-07-23 20:00', 55, 144, 1);\r\nINSERT INTO `schedule` VALUES (34, 45, 20, '2019-07-22 20:30', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (35, 8, 25, '2019-07-24 00:00', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (36, 7, 1, '2019-07-24 20:10', 55, 144, 1);\r\nINSERT INTO `schedule` VALUES (37, 7, 20, '2019-07-22 15:30', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (38, 8, 20, '2019-07-23 14:20', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (39, 2, 1, '2019-07-21 10:10', 48, 143, 1);\r\nINSERT INTO `schedule` VALUES (40, 2, 1, '2019-07-22 10:10', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (41, 8, 20, '2019-07-23 21:45', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (42, 11, 25, '2019-07-23 12:30', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (43, 8, 20, '2019-07-23 10:40', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (44, 29, 25, '2019-07-25 00:00', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (45, 8, 1, '2019-07-23 10:20', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (46, 2, 20, '2019-07-22 19:30', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (47, 8, 1, '2019-07-24 10:20', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (48, 37, 25, '2019-07-23 20:00', 38, 144, 0);\r\nINSERT INTO `schedule` VALUES (49, 45, 20, '2019-07-23 20:20', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (50, 7, 20, '2019-07-23 16:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (51, 46, 20, '2019-07-23 15:15', 68, 144, 1);\r\nINSERT INTO `schedule` VALUES (52, 3, 1, '2019-07-23 10:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (53, 14, 20, '2019-07-24 13:00', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (54, 46, 1, '2019-07-23 19:20', 67, 144, 1);\r\nINSERT INTO `schedule` VALUES (55, 29, 20, '2019-07-24 17:10', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (56, 9, 1, '2019-07-24 09:40', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (57, 46, 1, '2019-07-24 19:30', 66, 144, 1);\r\nINSERT INTO `schedule` VALUES (58, 32, 20, '2019-07-23 09:30', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (59, 24, 3, '2019-07-25 13:35', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (60, 49, 25, '2019-07-24 10:00', 50, 144, 1);\r\nINSERT INTO `schedule` VALUES (61, 37, 20, '2019-07-23 22:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (62, 5, 1, '2019-07-23 10:15', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (63, 51, 3, '2019-07-23 17:05', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (64, 36, 25, '2019-07-23 19:30', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (65, 35, 3, '2019-07-24 19:05', 45, 138, 1);\r\nINSERT INTO `schedule` VALUES (66, 29, 20, '2019-07-24 07:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (67, 4, 26, '2019-07-23 20:00', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (68, 16, 3, '2019-07-23 18:05', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (69, 10, 20, '2019-07-24 13:35', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (70, 33, 26, '2019-07-24 21:00', 22, 144, 1);\r\nINSERT INTO `schedule` VALUES (71, 4, 1, '2019-07-23 09:45', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (72, 10, 1, '2019-07-23 19:20', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (73, 24, 3, '2019-07-25 21:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (74, 11, 21, '2019-07-23 14:15', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (75, 23, 26, '2019-07-24 13:00', 25, 144, 1);\r\nINSERT INTO `schedule` VALUES (76, 4, 1, '2019-07-24 09:50', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (77, 31, 3, '2019-07-26 12:45', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (78, 37, 26, '2019-07-24 19:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (79, 11, 21, '2019-07-23 15:25', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (80, 10, 1, '2019-07-24 20:00', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (81, 10, 26, '2019-07-23 22:05', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (82, 39, 21, '2019-07-23 20:05', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (83, 11, 1, '2019-07-23 21:10', 44, 143, 1);\r\nINSERT INTO `schedule` VALUES (84, 5, 21, '2019-07-24 10:20', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (85, 24, 26, '2019-07-24 17:30', 25, 144, 1);\r\nINSERT INTO `schedule` VALUES (86, 31, 26, '2019-07-22 19:00', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (87, 5, 1, '2019-07-24 09:30', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (88, 11, 21, '2019-07-24 22:15', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (89, 17, 26, '2019-07-22 00:00', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (90, 35, 3, '2019-07-24 18:40', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (91, 39, 1, '2019-07-24 20:25', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (92, 12, 21, '2019-07-23 14:10', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (93, 12, 26, '2019-07-23 22:00', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (94, 24, 5, '2019-07-21 19:55', 54, 142, 1);\r\nINSERT INTO `schedule` VALUES (95, 12, 21, '2019-07-23 16:05', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (96, 6, 1, '2019-07-23 10:20', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (97, 8, 26, '2019-07-23 10:00', 25, 144, 1);\r\nINSERT INTO `schedule` VALUES (98, 47, 24, '2019-07-28 14:45', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (99, 12, 21, '2019-07-24 10:00', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (100, 6, 1, '2019-07-23 21:10', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (101, 29, 26, '2019-07-23 20:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (102, 12, 1, '2019-07-24 10:10', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (103, 30, 21, '2019-07-23 13:10', 35, 141, 1);\r\nINSERT INTO `schedule` VALUES (104, 12, 1, '2019-07-24 20:40', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (105, 30, 21, '2019-07-23 21:05', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (106, 25, 26, '2019-07-24 23:00', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (107, 28, 21, '2019-07-24 16:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (108, 14, 1, '2019-07-23 19:20', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (109, 1, 15, '2019-07-23 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (110, 26, 1, '2019-07-24 10:20', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (111, 51, 22, '2019-07-21 00:00', 59, 144, 1);\r\nINSERT INTO `schedule` VALUES (112, 40, 1, '2019-07-24 22:00', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (113, 4, 18, '2019-07-25 08:05', 65, 144, 1);\r\nINSERT INTO `schedule` VALUES (114, 36, 22, '2019-07-21 00:00', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (115, 34, 22, '2019-07-23 13:15', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (116, 31, 22, '2019-07-23 13:20', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (117, 16, 17, '2019-07-24 09:10', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (118, 15, 1, '2019-07-23 20:30', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (119, 27, 1, '2019-07-24 09:50', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (120, 47, 18, '2019-07-25 16:30', 54, 144, 1);\r\nINSERT INTO `schedule` VALUES (121, 47, 1, '2019-07-24 20:40', 56, 144, 1);\r\nINSERT INTO `schedule` VALUES (122, 43, 18, '2019-07-24 04:25', 28, 142, 1);\r\nINSERT INTO `schedule` VALUES (123, 1, 15, '2019-07-21 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (124, 16, 1, '2019-07-23 21:20', 41, 144, 1);\r\nINSERT INTO `schedule` VALUES (125, 34, 18, '2019-07-21 17:15', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (126, 7, 15, '2019-07-22 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (127, 28, 1, '2019-07-24 20:30', 41, 144, 1);\r\nINSERT INTO `schedule` VALUES (128, 17, 1, '2019-07-23 14:15', 42, 144, 1);\r\nINSERT INTO `schedule` VALUES (129, 1, 15, '2019-07-21 20:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (130, 29, 1, '2019-07-24 09:00', 42, 144, 1);\r\nINSERT INTO `schedule` VALUES (131, 7, 15, '2019-07-22 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (132, 36, 22, '2019-07-24 16:20', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (133, 3, 16, '2019-07-24 10:10', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (134, 13, 15, '2019-07-23 10:30', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (135, 25, 4, '2019-07-21 05:25', 32, 136, 1);\r\nINSERT INTO `schedule` VALUES (136, 1, 2, '2019-07-23 10:05', 34, 139, 1);\r\nINSERT INTO `schedule` VALUES (137, 13, 15, '2019-07-23 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (138, 7, 2, '2019-07-23 22:15', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (139, 48, 22, '2019-07-24 15:25', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (140, 49, 23, '2019-07-21 15:15', 42, 144, 1);\r\nINSERT INTO `schedule` VALUES (141, 13, 15, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (142, 30, 22, '2019-07-23 16:15', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (143, 7, 15, '2019-07-24 18:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (144, 13, 2, '2019-07-24 17:10', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (145, 7, 15, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (146, 25, 2, '2019-07-23 19:30', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (147, 40, 23, '2019-07-23 10:30', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (148, 37, 2, '2019-07-24 10:05', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (149, 26, 23, '2019-07-23 20:15', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (150, 44, 2, '2019-07-24 19:10', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (151, 24, 2, '2019-07-22 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (152, 32, 23, '2019-07-23 13:30', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (153, 36, 2, '2019-07-23 00:00', 32, 142, 1);\r\nINSERT INTO `schedule` VALUES (154, 51, 2, '2019-07-24 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (155, 10, 23, '2019-07-23 13:20', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (156, 2, 15, '2019-07-21 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (157, 33, 23, '2019-07-23 19:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (158, 23, 2, '2019-07-23 09:00', 35, 142, 1);\r\nINSERT INTO `schedule` VALUES (159, 2, 15, '2019-07-21 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (160, 35, 2, '2019-07-24 21:00', 35, 143, 1);\r\nINSERT INTO `schedule` VALUES (161, 8, 15, '2019-07-21 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (162, 50, 2, '2019-07-25 20:05', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (163, 8, 15, '2019-07-21 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (164, 22, 2, '2019-07-22 00:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (165, 27, 23, '2019-07-23 16:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (166, 2, 15, '2019-07-21 20:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (167, 34, 2, '2019-07-23 00:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (168, 43, 2, '2019-07-24 00:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (169, 47, 24, '2019-07-23 16:10', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (170, 2, 15, '2019-07-23 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (171, 28, 24, '2019-07-23 15:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (172, 8, 15, '2019-07-23 10:30', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (173, 29, 24, '2019-07-21 15:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (174, 20, 3, '2019-07-23 09:00', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (175, 8, 15, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (176, 32, 3, '2019-07-24 12:15', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (177, 34, 24, '2019-07-24 10:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (178, 8, 15, '2019-07-24 13:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (179, 4, 3, '2019-07-23 15:00', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (180, 8, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (181, 10, 3, '2019-07-24 17:00', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (182, 3, 15, '2019-07-22 09:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (183, 42, 24, '2019-07-24 13:35', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (184, 25, 3, '2019-07-22 08:00', 26, 144, 1);\r\nINSERT INTO `schedule` VALUES (185, 3, 15, '2019-07-22 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (186, 9, 15, '2019-07-22 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (187, 38, 15, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (188, 37, 3, '2019-07-24 14:05', 26, 144, 1);\r\nINSERT INTO `schedule` VALUES (189, 35, 24, '2019-07-24 16:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (190, 38, 15, '2019-07-25 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (191, 44, 3, '2019-07-25 09:00', 26, 144, 1);\r\nINSERT INTO `schedule` VALUES (192, 3, 15, '2019-07-25 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (193, 1, 4, '2019-07-22 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (194, 7, 4, '2019-07-23 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (195, 35, 24, '2019-07-24 16:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (196, 4, 15, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (197, 13, 4, '2019-07-24 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (198, 10, 15, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (199, 45, 4, '2019-07-25 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (200, 10, 15, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (201, 20, 4, '2019-07-23 23:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (202, 10, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (203, 20, 4, '2019-07-24 23:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (204, 5, 15, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (205, 4, 4, '2019-07-23 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (206, 10, 4, '2019-07-24 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (207, 11, 15, '2019-07-23 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (208, 16, 21, '2019-07-23 13:25', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (209, 39, 15, '2019-07-23 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (210, 5, 15, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (211, 11, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (212, 37, 4, '2019-07-23 15:05', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (213, 22, 22, '2019-07-23 16:05', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (214, 44, 4, '2019-07-24 14:10', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (215, 6, 15, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (216, 24, 5, '2019-07-23 04:00', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (217, 12, 15, '2019-07-23 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (218, 12, 15, '2019-07-24 09:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (219, 42, 22, '2019-07-24 17:00', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (220, 6, 15, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (221, 1, 16, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (222, 36, 5, '2019-07-21 14:54', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (223, 13, 16, '2019-07-23 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (224, 20, 23, '2019-07-24 18:45', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (225, 15, 5, '2019-07-23 04:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (226, 7, 16, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (227, 42, 5, '2019-07-24 04:00', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (228, 7, 16, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (229, 4, 23, '2019-07-24 14:15', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (230, 27, 5, '2019-07-23 05:05', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (231, 13, 15, '2019-07-24 18:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (232, 2, 16, '2019-07-23 11:00', 30, 140, 1);\r\nINSERT INTO `schedule` VALUES (233, 47, 23, '2019-07-23 20:15', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (234, 2, 16, '2019-07-23 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (235, 2, 16, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (236, 15, 23, '2019-07-24 20:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (237, 8, 16, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (238, 11, 5, '2019-07-24 14:57', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (239, 2, 16, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (240, 27, 5, '2019-07-21 14:58', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (241, 41, 5, '2019-07-24 07:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (242, 16, 24, '2019-07-23 20:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (243, 3, 16, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (244, 22, 5, '2019-07-22 05:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (245, 38, 16, '2019-07-23 19:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (246, 34, 5, '2019-07-23 05:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (247, 9, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (248, 41, 24, '2019-07-23 12:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (249, 43, 5, '2019-07-24 05:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (250, 9, 16, '2019-07-24 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (251, 17, 24, '2019-07-24 20:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (252, 4, 16, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (253, 10, 16, '2019-07-24 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (254, 30, 24, '2019-07-23 14:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (255, 5, 16, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (256, 22, 24, '2019-07-23 14:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (257, 5, 16, '2019-07-23 19:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (258, 5, 16, '2019-07-24 13:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (259, 39, 16, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (260, 6, 16, '2019-07-23 00:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (261, 12, 16, '2019-07-24 16:00', 20, 144, 1);\r\nINSERT INTO `schedule` VALUES (262, 1, 17, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (263, 7, 17, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (264, 13, 17, '2019-07-24 07:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (265, 7, 17, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (266, 2, 17, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (267, 8, 17, '2019-07-23 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (268, 2, 17, '2019-07-24 09:20', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (269, 8, 17, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (270, 3, 17, '2019-07-23 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (271, 9, 17, '2019-07-23 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (272, 38, 17, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (273, 4, 17, '2019-07-23 14:00', 20, 144, 1);\r\nINSERT INTO `schedule` VALUES (274, 10, 17, '2019-07-24 14:05', 20, 144, 1);\r\nINSERT INTO `schedule` VALUES (275, 11, 17, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (276, 11, 17, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (277, 12, 17, '2019-07-23 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (278, 12, 17, '2019-07-24 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (279, 6, 17, '2019-07-23 09:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (280, 39, 17, '2019-07-23 21:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (281, 39, 17, '2019-07-24 00:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (282, 38, 17, '2019-07-24 08:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (283, 1, 18, '2019-07-23 08:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (284, 7, 18, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (285, 13, 18, '2019-07-24 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (286, 1, 18, '2019-07-24 16:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (287, 2, 18, '2019-07-23 17:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (288, 2, 18, '2019-07-23 09:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (289, 2, 18, '2019-07-23 14:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (290, 2, 18, '2019-07-24 10:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (291, 2, 18, '2019-07-24 13:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (292, 3, 18, '2019-07-23 12:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (293, 9, 18, '2019-07-23 20:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (294, 3, 18, '2019-07-23 15:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (295, 9, 18, '2019-07-24 10:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (296, 9, 18, '2019-07-24 11:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (297, 38, 18, '2019-07-24 21:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (298, 10, 18, '2019-07-23 08:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (299, 4, 18, '2019-07-23 11:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (300, 4, 18, '2019-07-24 14:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (301, 10, 18, '2019-07-24 21:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (302, 5, 18, '2019-07-23 08:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (303, 11, 18, '2019-07-24 11:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (304, 39, 18, '2019-07-24 15:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (305, 6, 18, '2019-07-23 10:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (306, 12, 18, '2019-07-24 12:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (307, 12, 18, '2019-07-24 18:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (308, 1, 27, '2019-07-23 00:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (309, 7, 27, '2019-07-24 19:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (310, 8, 27, '2019-07-23 20:00', 40, 140, 1);\r\nINSERT INTO `schedule` VALUES (311, 4, 27, '2019-07-23 16:00', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (312, 11, 27, '2019-07-24 19:15', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (313, 8, 27, '2019-07-24 15:00', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (314, 8, 20, '2019-07-18 04:04', 45, 144, 1);\r\n\r\n-- ----------------------------\r\n-- Table structure for user\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `user`;\r\nCREATE TABLE `user`  (\r\n  `user_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '会员编号',\r\n  `user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '会员账号',\r\n  `user_pwd` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '会员密码',\r\n  `user_email` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '会员邮箱',\r\n  `user_role` int(10) NOT NULL DEFAULT 0 COMMENT '会员权限（默认为0）\\r\\n0：普通会员 1：管理员',\r\n  `user_headImg` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '会员头像',\r\n  PRIMARY KEY (`user_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of user\r\n-- ----------------------------\r\nINSERT INTO `user` VALUES (1, 'user', 'user', '33734872621@qq.com', 0, '../upload/head/f6337987771546f9a143fc5206f047f4.jpg');\r\nINSERT INTO `user` VALUES (2, 'admin', 'admin', '3456872621@qq.com', 1, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (3, 'wxj', 'wxj', '937872111@126.com', 1, '../upload/head/de9d930c96e240bc9f4f91b914e5dddb.jpg');\r\nINSERT INTO `user` VALUES (4, 'lpf', 'lpf', '23546211543@qq.com', 0, '../upload/head/85c888cf36d649d6aaea58f19cc8c143.jpg');\r\nINSERT INTO `user` VALUES (5, 'wzw', 'wzw', '2154698421@126.com', 0, '../upload/head/bdc1cf2d9b9d4d5ca5d7a34f2ebfc5b3.jpg');\r\nINSERT INTO `user` VALUES (6, 'hzw', 'hzw', 'a487953215@163.com', 0, '../upload/head/demo.jpg');\r\nINSERT INTO `user` VALUES (7, 'lsw', 'lsw', '3215644123@qq.com', 0, '../upload/head/84c69b60d91e4c079e249a6cd09ef91c.jpg');\r\nINSERT INTO `user` VALUES (8, 'bg12356484', '6484', '910050724@qq.com', 0, '../upload/head/demo.jpg');\r\nINSERT INTO `user` VALUES (9, 'ao13546954', '6954', 'hsw236413512@163.com', 0, NULL);\r\nINSERT INTO `user` VALUES (19, 'jd15154478', '4478', '5648132142@163.com', 0, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (20, 'sn46845411', '5411', 'gs15648231@126.com', 0, '../upload/head/84c69b60d91e4c079e249a6cd09ef91c.jpg');\r\nINSERT INTO `user` VALUES (21, 'gs12314864', '4864', '2154678122@qq.com', 0, '../upload/head/84c69b60d91e4c079e249a6cd09ef91c.jpg');\r\nINSERT INTO `user` VALUES (22, 'jd12315164', '5164', '211215484@qq.com', 0, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (23, 'kl15645641', '5641', 'g123456412@163.com', 0, '../upload/head/dd7cf74e264247ffbe888c4e163fb9ed.jpg');\r\nINSERT INTO `user` VALUES (24, 'kd1231854', '1854', '123484547@qq.com', 0, NULL);\r\nINSERT INTO `user` VALUES (25, 'tw1123484', '3484', '988744641@qq.com', 0, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (26, 'if48648411', '8411', 'u365484741@163.com', 0, '../upload/head/dd7cf74e264247ffbe888c4e163fb9ed.jpg');\r\nINSERT INTO `user` VALUES (27, 'od1561487', '1487', '1564562314@qq.com', 0, NULL);\r\nINSERT INTO `user` VALUES (28, 'jd54687233', '7233', '165484754@qq.com', 0, NULL);\r\n\r\nSET FOREIGN_KEY_CHECKS = 1;\r\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>com.movie</groupId>\n  <artifactId>Movie</artifactId>\n  <packaging>war</packaging>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>Movie Maven Webapp</name>\n  <url>http://maven.apache.org</url>\n  <dependencies>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>3.8.1</version>\n      <scope>test</scope>\n    </dependency>\n    \n    <!-- mysql驱动包 -->\n\t<dependency>\n\t    <groupId>mysql</groupId>\n\t    <artifactId>mysql-connector-java</artifactId>\n\t    <version>8.0.12</version>\n\t</dependency>\n\t\n    <!-- mybatis核心包 -->\n\t<dependency>\n\t    <groupId>org.mybatis</groupId>\n\t    <artifactId>mybatis</artifactId>\n\t    <version>3.4.6</version>\n\t</dependency>\n\t\n\t<!-- mybatis-spring适配器 -->\n\t<dependency>\n\t    <groupId>org.mybatis</groupId>\n\t    <artifactId>mybatis-spring</artifactId>\n\t    <version>2.0.1</version>\n\t</dependency>\n\t\n\t<!-- spring框架 --> \n\t<dependency>\n\t    <groupId>org.springframework</groupId>\n\t    <artifactId>spring-context</artifactId>\n\t    <version>5.1.6.RELEASE</version>\n\t</dependency>\n\n\t<!-- AOP支持 --> \n\t<dependency>\n\t    <groupId>org.aspectj</groupId>\n\t    <artifactId>aspectjweaver</artifactId>\n\t    <version>1.9.3</version>\n\t</dependency>\n\t\n\t<!-- spring 事务 --> \n\t<dependency>\n\t\t<groupId>org.springframework</groupId>\n\t\t<artifactId>spring-tx</artifactId>\n\t\t<version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- spring jdbc --> \n\t<dependency>\n\t\t<groupId>org.springframework</groupId>\n\t\t<artifactId>spring-jdbc</artifactId>\n\t\t<version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- 阿里巴巴连接池 -->\n    <dependency>\n\t\t<groupId>com.alibaba</groupId>\n\t\t<artifactId>druid</artifactId>\n\t\t<version>1.0.27</version>\n    </dependency>\n\n\t<!-- spring 扩展包 --> \n\t<dependency>\n\t\t<groupId>org.springframework</groupId>\n\t\t<artifactId>spring-context-support</artifactId>\n\t\t<version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- spring-webmvc框架 -->\n\t<dependency>\n\t    <groupId>org.springframework</groupId>\n\t    <artifactId>spring-webmvc</artifactId>\n\t    <version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- 引入jackson相关的包 -->\n\t<dependency>\n        <groupId>com.fasterxml.jackson.core</groupId>\n        <artifactId>jackson-databind</artifactId>\n        <version>2.9.3</version>\n    </dependency>\n    <dependency>\n        <groupId>com.fasterxml.jackson.core</groupId>\n        <artifactId>jackson-core</artifactId>\n        <version>2.9.3</version>\n    </dependency>\n    <dependency>\n        <groupId>com.fasterxml.jackson.core</groupId>\n        <artifactId>jackson-annotations</artifactId>\n        <version>2.9.3</version>\n    </dependency>\n    \n    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->\n\t<dependency>\n\t    <groupId>com.alibaba</groupId>\n\t    <artifactId>fastjson</artifactId>\n\t    <version>1.2.51</version>\n\t</dependency>\n    \n    <!-- https://mvnrepository.com/artifact/com.thetransactioncompany/cors-filter -->\n    <!-- 跨域 -->\n\t<dependency>\n\t    <groupId>com.thetransactioncompany</groupId>\n\t    <artifactId>cors-filter</artifactId>\n\t    <version>2.5</version>\n\t</dependency>\n    \n    <!-- 视图引擎freemarker -->\n\t<dependency>\n\t\t<groupId>org.freemarker</groupId>\n\t\t<artifactId>freemarker</artifactId>\n\t\t<version>2.3.23</version>\n\t</dependency>\n\t\n\t<!-- pagerHelp 包  mybatis分页-->\n\t <dependency>\n\t \t<groupId>com.github.pagehelper</groupId>\n\t \t<artifactId>pagehelper</artifactId> \n\t \t<version>5.1.4</version>\n\t</dependency>\n\t\n\t<!-- jstl依赖包 -->\n\t<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->\n\t<dependency>\n\t    <groupId>javax.servlet</groupId>\n\t    <artifactId>jstl</artifactId>\n\t    <version>1.2</version>\n\t</dependency>\n\t\n\t<!-- 文件上传配置 -->\n\t <dependency>\n            <groupId>commons-fileupload</groupId>\n            <artifactId>commons-fileupload</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.5</version>\n \t</dependency>\n \t\n \t<!-- 时间类型数据 -->\n \t<dependency>\n      <groupId>joda-time</groupId>\n      <artifactId>joda-time</artifactId>\n      <version>2.9.9</version>\n    </dependency>\n\n  </dependencies>\n  <build>\n    <finalName>Movie</finalName>\n    <plugins>\n    \t<plugin>\n    \t\t<groupId>org.apache.maven.plugins</groupId>\n    \t\t <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n    \t</plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "src/main/java/com/controller/CommentController.java",
    "content": "package com.controller;\n\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport com.alibaba.fastjson.JSONObject;\nimport com.entity.Comment;\nimport com.entity.User;\nimport com.github.pagehelper.PageInfo;\nimport com.service.ICommentService;\nimport com.service.IMovieService;\nimport com.service.IUserService;\n\n/**\n *  评论管理模块\n * @author Wxj\n */\n@Controller\n@RequestMapping(\"/comment\")\npublic class CommentController {\n\n\t@Resource\n\tprivate ICommentService commentService;\n\t@Resource\n\tprivate IUserService userService;\n\t@Resource\n\tprivate IMovieService movieService;\n\t//用户： 修改评论、增加评论\n\t\t//管理员：x 删除评论、 修改评论\n\t\t//x查询用户的评论\n\t@RequestMapping(\"findAllComments\")\n\t@ResponseBody\n\tpublic JSONObject findAllComments() {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Comment> list = commentService.findAllComments();\n\t\tfor(Comment comment: list) {\n\t\t\tcomment.setComment_user(userService.findUserById(comment.getUser_id()));\n\t\t}\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\",\"\");\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t//测试 info.getTotal\n\t@RequestMapping(\"findAllCommentsPage\")\n\t@ResponseBody\n\tpublic JSONObject findAllCommentsPage(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,String keyword) {\n\t\tPageInfo<Comment> info = commentService.findAllCommentsBySplitPage(page, limit, keyword);\n\t\t//System.out.println(info);\n\t\tfor(Comment comment : info.getList()) {\n\t\t\tcomment.setComment_user(userService.findUserById(comment.getUser_id()));\n\t\t}\n\t\tJSONObject obj = new JSONObject();\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"addCommentByUser\")\n\t@ResponseBody\n\tpublic JSONObject addCommentByUser(@RequestParam(\"movie_id\")long movie_id,@RequestParam(\"comment_content\")String comment_content,HttpServletRequest request) {\n\t\tUser user = (User)request.getSession().getAttribute(\"user\");\n\t\tJSONObject obj = new JSONObject();\n\t\tif(user == null) {\n\t\t\tobj.put(\"code\",200);\n\t\t\tobj.put(\"msg\", \"您未登录,登录之后才可评论~\");\n\t\t}else {\n\t\t\tComment comment = new Comment();\n\t\t\tcomment.setComment_content(comment_content);\n\t\t\tcomment.setMovie_id(movie_id);\n\t\t\tcomment.setUser_id(user.getUser_id());\n\t\t\tcomment.setComment_time(new Date());\n\t\t\tInteger rs = commentService.addComemnt(comment);\n\t\t\tif(rs > 0) {\n\t\t\t\tInteger rs2 = movieService.addCommentCount(comment.getMovie_id());\n\t\t\t\tif(rs2 > 0) {\n\t\t\t\t\tobj.put(\"code\", 0);\n\t\t\t\t\tobj.put(\"msg\", \"评论成功~\");\n\t\t\t\t}else {\n\t\t\t\t\tobj.put(\"code\",200);\n\t\t\t\t\tobj.put(\"msg\", \"评论失败2~\");\n\t\t\t\t}\n\t\t\t}else {\n\t\t\t\tobj.put(\"code\",200);\n\t\t\t\tobj.put(\"msg\", \"评论失败~\");\n\t\t\t}\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"updateComment\")\n\t@ResponseBody\n\tpublic JSONObject updateComment(@RequestParam(\"comment_id\")long comment_id,@RequestParam(\"comment_content\")String comment_content) {\n\t\tJSONObject obj = new JSONObject();\n\t\tComment comment = this.commentService.findCommentById(comment_id);\n\t\tcomment.setComment_time(new Date());\n\t\tcomment.setComment_content(comment_content);\n\t\tInteger rs = commentService.updateComment(comment);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"修改成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\",200);\n\t\t\tobj.put(\"msg\", \"修改失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"deleteComemnt\")\n\t@ResponseBody\n\tpublic JSONObject deleteComment(@RequestParam(\"comment_id\")long comment_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tInteger rs2 = movieService.delCommentCount(commentService.findCommentById(comment_id).getMovie_id());\n\t\tInteger rs = commentService.deleteComment(comment_id);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"删除成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"删除失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findCommentsByUserName\")\n\t@ResponseBody\n\tpublic JSONObject findCommentsByUserName(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,@RequestParam(\"user_name\")String user_name) {\n\t\tPageInfo<Comment> info = commentService.findCommentsByUserName(page, limit, user_name);\n\t\t//System.out.println(info);\n\t\tfor(Comment comment : info.getList()) {\n\t\t\tcomment.setComment_user(userService.findUserById(comment.getUser_id()));\n\t\t}\n\t\tJSONObject obj = new JSONObject();\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\treturn obj;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/controller/MovieController.java",
    "content": "package com.controller;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Random;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.entity.Cinema;\nimport com.entity.Movie;\nimport com.service.ICinemaService;\nimport com.service.IMovieService;\nimport com.util.UUIDUtil;\n\n/**\n * 电影管理模块\n * @author Wxj\n */\n@Controller\n@RequestMapping(\"/movie\")\npublic class MovieController {\n\t@Resource\n\tprivate IMovieService movieService;\n\t@Resource\n\tprivate ICinemaService cinemaService;\n\t//1.电影详情页 findid\n\t//2.首页电影列表 + name搜索 + type搜素 + 时间、参评人数、评分排序 \n\t//3.增加、删除、修改\n\t@RequestMapping(\"findMovieById\")\n\t@ResponseBody\n\tpublic JSONObject findMovieById(@RequestParam(\"movie_id\")long movie_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tMovie movie = movieService.findMovieById(movie_id);\n\t\tList<Cinema> list = this.cinemaService.findCinemasByMovieId(movie_id);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"data\", movie);\n\t\tobj.put(\"cinemaList\",list);\n\t\tobj.put(\"cinemaCount\",list.size());\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllMovies\")\n\t@ResponseBody\n\tpublic JSONObject findAllMovies() {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Movie> list = movieService.findAllMovies(1);\n\t\tList<Movie> upcomingList = movieService.findAllMovies(0);\n\t\tList<Movie> offList = movieService.sortMovieByBoxOffice();\n\t\tString type[] = {\"喜剧\",\"动作\",\"爱情\",\"动画\",\"科幻\",\"惊悚\",\"冒险\",\"犯罪\",\"悬疑\"};\n\t\tArrayList<Object> typeArr = new ArrayList<Object>();\n\t\tfor(int i = 0;i < type.length;i++) {\n\t\t\tList<Movie> movieList = this.movieService.findMoviesLikeType(type[i]);\n\t\t\tfloat boxOffice = 0;\n\t\t\tfor(int j = 0; j < movieList.size();j++) {\n\t\t\t\tboxOffice += movieList.get(j).getMovie_boxOffice();\n\t\t\t}\n\t\t\tJSONObject typeJson = new JSONObject();\n\t\t\ttypeJson.put(type[i], boxOffice);\n\t\t\ttypeArr.add(typeJson);\n\t\t}\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"upcomingCount\",upcomingList.size());\n\t\tobj.put(\"data\", list);\n\t\tobj.put(\"data1\", upcomingList);\n\t\tobj.put(\"sort\", offList);\n\t\tobj.put(\"type\", typeArr);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findMoviesByName\")\n\t@ResponseBody\n\tpublic JSONObject findMoviesByName(@RequestParam(\"name\") String name) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Movie> list = movieService.findMoviesLikeName(name);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findMoviesByType\")\n\t@ResponseBody\n\tpublic JSONObject findMoviesByType(@RequestParam(\"type\") String type) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Movie> list = movieService.findMoviesLikeType(type);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"sortAllMovies\")\n\t@ResponseBody\n\tpublic JSONObject sortAllMovies(@RequestParam(\"order\") String order) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Movie> list = new ArrayList<Movie>();\n\t\tswitch (order) {\n\t\t\tcase \"热门\":\n\t\t\t\tlist = movieService.sortMovieByCount();\n\t\t\t\tbreak;\n\t\t\tcase \"时间\":\n\t\t\t\tlist = movieService.sortMovieByDate();\n\t\t\t\tbreak;\n\t\t\tcase \"评价\":\n\t\t\t\tlist = movieService.sortMovieByScore();\n\t\t\t\tbreak;\n\t\t}\n\t\tobj.put(\"code\",0);\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"deleteMovie\")\n\t@ResponseBody\n\tpublic JSONObject deleteMovie(@RequestParam(\"movie_id\") long movie_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tInteger rs = movieService.deleteMovie(movie_id);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\",0);\n\t\t\tobj.put(\"msg\",\"下架成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"下架失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"addMovie\")\n\t@ResponseBody\n\tpublic JSONObject addMovie(@RequestParam(value=\"file\",required=false) MultipartFile file,Movie movie,HttpServletRequest request) throws IOException  {\n\t\tString str = file.getOriginalFilename();\n\t\tSystem.out.println(\"file:\" + str);\n\t\tString name = UUIDUtil.getUUID() + str.substring(str.lastIndexOf(\".\"));\n\t\tSystem.out.println(\"name:\" + name);\n\t\tString path = request.getServletContext().getRealPath(\"/upload/movies\") + \"/\" + name;\n\t\tSystem.out.println(\"path:\" + path);\n\t\tString filePath = \"../upload/movies/\" + name;\n\t\tmovie.setMovie_picture(filePath);\n\t\tDate date = new Date();\n\t\tjava.sql.Date releaseDate = new java.sql.Date(date.getYear(), date.getMonth(), date.getDay());\n\t\t//SimpleDateFormat dateFormat = new SimpleDateFormat(\"YYYY-MM-dd\");\n\t\tfloat random = 5 + (new Random().nextFloat() * 4);\n\t\tDecimalFormat fnum = new DecimalFormat(\"##0.0\");  \n\t\tString score = fnum.format(random);\n\t\tmovie.setMovie_score(Float.parseFloat(score));\n\t\tmovie.setReleaseDate(releaseDate);\n\t\tInteger rs = movieService.addMovie(movie);\n\t\tJSONObject obj = new JSONObject();\n\t\tif(rs > 0) {\n\t\t\tfile.transferTo(new File(path));\n\t\t\tSystem.out.println(\"文件写入成功,Path:\" + path);\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"添加成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"添加失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"updateMovie\")\n\t@ResponseBody\n\tpublic JSONObject updateMovie(@RequestParam(value=\"file\",required=false)MultipartFile file,Movie movie,HttpServletRequest request) throws IOException{\n\t\tJSONObject obj = new JSONObject();\n\t\tif(file != null) {\n\t\t\tString str = file.getOriginalFilename();\n\t\t\tSystem.out.println(\"file:\" + str);\n\t\t\tString name = UUIDUtil.getUUID() + str.substring(str.lastIndexOf(\".\"));\n\t\t\tSystem.out.println(\"name:\" + name);\n\t\t\tString path = request.getServletContext().getRealPath(\"/upload/movies\") + \"/\" + name;\n\t\t\tSystem.out.println(\"path:\" + path);\n\t\t\tString filePath = \"../upload/movies/\" + name;\n\t\t\tfile.transferTo(new File(path));\n\t\t\tSystem.out.println(\"文件写入成功,Path:\" + path);\n\t\t\tmovie.setMovie_picture(filePath);\n\t\t}else {\n\t\t\tMovie oldMovie = this.movieService.findMovieById(movie.getMovie_id());\n\t\t\tmovie.setMovie_picture(oldMovie.getMovie_picture());\n\t\t}\n\t\tInteger rs = movieService.updateMovie(movie);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"修改成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"修改失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/controller/OrderController.java",
    "content": "package com.controller;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.entity.Order;\nimport com.entity.User;\nimport com.github.pagehelper.PageInfo;\nimport com.service.IMovieService;\nimport com.service.IOrderService;\nimport com.service.IScheduleService;\n\n@Controller\n@RequestMapping(\"/order\")\npublic class OrderController {\n\t@Resource\n\tprivate IOrderService orderService;\n\t@Resource\n\tprivate IScheduleService scheduleService;  //支付、退票成功 座位+-\n\t@Resource\n\tprivate IMovieService movieService; //支付、退票成功  票房+-\n\t//查看订单是否 是支付的（返回给前端的数据）\n\t\n\t@RequestMapping(\"findOrderById\")\n\t@ResponseBody\n\tpublic JSONObject findOrderById(@RequestParam(\"order_id\")String order_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tOrder order = orderService.findOrderById(order_id);\n\t\tList<Order> list = new ArrayList<Order>();\n\t\tlist.add(order);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\",list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findOrderByUserName\")\n\t@ResponseBody\n\tpublic JSONObject findOrderByUserName(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,@RequestParam(\"user_name\")String user_name) {\n\t\tPageInfo<Order> info = orderService.findOrdersByUserName(page, limit, user_name);\n\t\tJSONObject obj = new JSONObject();\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findRefundOrderByUser\")\n\t@ResponseBody\n\tpublic JSONObject findRefundOrderByUser(@RequestParam(\"user_name\")String user_name) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Order> list = this.orderService.findRefundOrderByUserName(user_name);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllOrders\")\n\t@ResponseBody\n\tpublic JSONObject findAllOrders() {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Order> list = orderService.findAllOrders();\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllOrdersPage\")\n\t@ResponseBody\n\tpublic JSONObject findAllOrdersPage(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,String keyword) {\n\t\tPageInfo<Order> info = orderService.findAllOrdersBySplitPage(page, limit, keyword);\n\t\tJSONObject obj = new JSONObject();\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllRefundOrder\")\n\t@ResponseBody\n\tpublic JSONObject findAllRefundOrder(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit) {\n\t\tJSONObject obj = new JSONObject();\n\t\tPageInfo<Order> info = orderService.findOrdersByState(page, limit, 0);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"buyTickets\")\n\t@ResponseBody\n\tpublic JSONObject buyTickets(@RequestParam(\"schedule_id\")long schedule_id,@RequestParam(\"position[]\")String[] position,@RequestParam(\"price\")int price,HttpServletRequest request) {\n\t\tUser user = (User)request.getSession().getAttribute(\"user\");\n\t\tJSONObject obj = new JSONObject();\n\t\tif(user == null) {\n\t\t\tobj.put(\"code\",200);\n\t\t\tobj.put(\"msg\", \"您未登录,登录之后才可购票~\");\n\t\t}else {\n\t\t\tint done = 0;\n\t\t\tint order_price = price / position.length;\n\t\t\tString user_id = \"\";\n\t\t\tswitch(String.valueOf(user.getUser_id()).length()) {\n\t\t\tcase 1: user_id = \"000\" + String.valueOf(user.getUser_id()); break;\n\t\t\tcase 2: user_id = \"00\" + String.valueOf(user.getUser_id()); break;\n\t\t\tcase 3: user_id = \"0\" + String.valueOf(user.getUser_id()); break;\n\t\t\tcase 4: user_id = String.valueOf(user.getUser_id()); break;\n\t\t\t}\n\t\t\tfor(int i = 0;i < position.length;i++) {\n\t\t\t\tOrder order = new Order();\n\t\t\t\tString order_id = \"\";\n\t\t\t\tDate date = new Date();\n\t\t\t\tSimpleDateFormat dateFormat = new SimpleDateFormat(\"YYYYMMdd\");\n\t\t\t\torder_id += dateFormat.format(date);\n\t\t\t\torder_id += user_id;\n\t\t\t\tString index = \"\";\n\t\t\t\tswitch(position[i].length()) {\n\t\t\t\t\tcase 4: \n\t\t\t\t\t\tindex = \"0\" + position[i].replaceAll(\"排\", \"0\");\n\t\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\tif(position[i].charAt(2) >= 48 && position[i].charAt(2) <= 57) {\n\t\t\t\t\t\t\tindex = \"0\" + position[i].replaceAll(\"排\", \"\");\n\t\t\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n\t\t\t\t\t\t}else {\n\t\t\t\t\t\t\tindex = position[i].replaceAll(\"排\", \"0\");\n\t\t\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\tindex = position[i].replaceAll(\"排\", \"\"); \n\t\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\torder_id += index;\n\t\t\t\torder.setOrder_id(order_id);\n\t\t\t\torder.setOrder_position(position[i]);\n\t\t\t\torder.setSchedule_id(schedule_id);\n\t\t\t\torder.setUser_id(user.getUser_id());\n\t\t\t\torder.setOrder_price(order_price);\n\t\t\t\torder.setOrder_time(new Date());\n\t\t\t\tInteger rs = this.orderService.addOrder(order);\n\t\t\t\tInteger rs1 = this.scheduleService.delScheduleRemain(schedule_id);\n\t\t\t\tdone++;\n\t\t\t}\n\t\t\tif(done == position.length) {\n\t\t\t\tfloat sum = (float)price/10000;\n\t\t\t\tInteger rs2 = this.movieService.changeMovieBoxOffice(sum, this.scheduleService.findScheduleById(schedule_id).getMovie_id());\n\t\t\t\tobj.put(\"code\",0);\n\t\t\t\tobj.put(\"msg\", \"购票成功~\");\n\t\t\t}else {\n\t\t\t\tobj.put(\"code\",200);\n\t\t\t\tobj.put(\"msg\", \"购票失败~\");\n\t\t\t}\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"applyForRefund\")\n\t@ResponseBody\n\tpublic JSONObject applyForRefund(@RequestParam(\"order_id\")String order_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tInteger rs = orderService.updateOrderStateToRefund(order_id);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"退票申请已发送~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"操作失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"agreeForRefund\")\n\t@ResponseBody\n\tpublic JSONObject agreeForRefund(@RequestParam(\"order_id\")String order_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tInteger rs = this.orderService.updateOrderStateToRefunded(order_id);\n\t\tif(rs > 0) {\n\t\t\tOrder order = this.orderService.findOrderById(order_id);\n\t\t\tint price = order.getOrder_price();\n\t\t\tlong movie_id = order.getOrder_schedule().getMovie_id();\n\t\t\tInteger rs2 = this.movieService.changeMovieBoxOffice((float)price/10000, movie_id);\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"退票成功\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"退票失败\");\n\t\t}\n\t\treturn obj;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/controller/ScheduleController.java",
    "content": "package com.controller;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.annotation.Resource;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.entity.Cinema;\nimport com.entity.Hall;\nimport com.entity.Movie;\nimport com.entity.Order;\nimport com.entity.Schedule;\nimport com.github.pagehelper.PageInfo;\nimport com.service.ICinemaService;\nimport com.service.IHallService;\nimport com.service.IMovieService;\nimport com.service.IScheduleService;\n\n@Controller\n@RequestMapping(\"/schedule\")\npublic class ScheduleController {\n\t@Resource\n\tprivate IScheduleService scheduleService;\n\t@Resource\n\tprivate IMovieService movieService;\n\t@Resource\n\tprivate ICinemaService cinemaService;\n\t@Resource\n\tprivate IHallService hallService;\n\t\n\t@RequestMapping(\"findScheduleById\")\n\t@ResponseBody\n\tpublic JSONObject findScheduleById(@RequestParam(\"schedule_id\")long schedule_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tSchedule schedule = scheduleService.findScheduleById(schedule_id);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"data\",schedule);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllScheduleByState\")\n\t@ResponseBody\n\tpublic JSONObject findAllScheduleByState(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,@RequestParam(\"schedule_state\")int schedule_state) {\n\t\tJSONObject obj = new JSONObject();\n\t\tPageInfo<Schedule> info = scheduleService.findAllScheduleByState(page, limit, schedule_state);\n\t\tArrayList<Integer> incomeArr = new ArrayList<Integer>();\n\t\tfor(int j = 0;j < info.getList().size();j++) {\n\t\t\tList<Order> orderList = info.getList().get(j).getOrderList();\n\t\t\tint income = 0;\n\t\t\tfor(int i = 0;i < orderList.size();i++) {\n\t\t\t\tincome += orderList.get(i).getOrder_price();\n\t\t\t}\n\t\t\tincomeArr.add(income);\n\t\t}\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\tobj.put(\"income\", incomeArr);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllSchedule\")\n\t@ResponseBody\n\tpublic JSONObject findAllSchedule(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit) {\n\t\tJSONObject obj = new JSONObject();\n\t\tPageInfo<Schedule> info = scheduleService.findAllSchedule(page, limit);\n\t\tList<Movie> movieList = movieService.findAllMovies(1);\n\t\tList<Cinema> cinemaList = cinemaService.findAllCinemas();\n\t\tArrayList<String> movieArr = new ArrayList<String>();\n\t\tArrayList<Integer> incomeArr = new ArrayList<Integer>();\n\t\tfor(int j = 0;j < info.getList().size();j++) {\n\t\t\tList<Order> orderList = info.getList().get(j).getOrderList();\n\t\t\tint income = 0;\n\t\t\tfor(int i = 0;i < orderList.size();i++) {\n\t\t\t\tincome += orderList.get(i).getOrder_price();\n\t\t\t}\n\t\t\tincomeArr.add(income);\n\t\t}\n\t\tfor(int i = 0;i < movieList.size();i++) {\n\t\t\tmovieArr.add(movieList.get(i).getMovie_cn_name());\n\t\t}\n\t\tArrayList<Object> cinema = new ArrayList<>();\n\t\tfor(int i = 0;i < cinemaList.size();i++) {\n\t\t\tJSONObject cinemaObj = new JSONObject();\n\t\t\tList<Hall> hallList = hallService.findHallByCinemaId(cinemaList.get(i).getCinema_id());\n\t\t\tArrayList<String> hallArr = new ArrayList<String>();\n\t\t\tfor(int j = 0;j < hallList.size();j++) {\n\t\t\t\thallArr.add(hallList.get(j).getHall_name());\n\t\t\t}\n\t\t\tcinemaObj.put(cinemaList.get(i).getCinema_name(), hallList);\n\t\t\tcinema.add(cinemaObj);\n\t\t}\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\tobj.put(\"movieName\", movieArr);\n\t\tobj.put(\"cinema\", cinema);\n\t\tobj.put(\"income\", incomeArr);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findScheduleByMovieName\")\n\t@ResponseBody\n\tpublic JSONObject findScheduleByMovieName(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,@RequestParam(\"movie_name\")String movie_name) {\n\t\tJSONObject obj = new JSONObject();\n\t\tPageInfo<Schedule> info = scheduleService.findScheduleByMovieName(page,limit,movie_name);\n\t\tArrayList<Integer> incomeArr = new ArrayList<Integer>();\n\t\tfor(int j = 0;j < info.getList().size();j++) {\n\t\t\tList<Order> orderList = info.getList().get(j).getOrderList();\n\t\t\tint income = 0;\n\t\t\tfor(int i = 0;i < orderList.size();i++) {\n\t\t\t\tincome += orderList.get(i).getOrder_price();\n\t\t\t}\n\t\t\tincomeArr.add(income);\n\t\t}\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\tobj.put(\"income\", incomeArr);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findOffScheduleByMovieName\")\n\t@ResponseBody\n\tpublic JSONObject findOffScheduleByMovieName(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,@RequestParam(\"movie_name\")String movie_name) {\n\t\tJSONObject obj = new JSONObject();\n\t\tPageInfo<Schedule> info = scheduleService.findOffScheduleByMovieName(page, limit, movie_name);\n\t\tArrayList<Integer> incomeArr = new ArrayList<Integer>();\n\t\tfor(int j = 0;j < info.getList().size();j++) {\n\t\t\tList<Order> orderList = info.getList().get(j).getOrderList();\n\t\t\tint income = 0;\n\t\t\tfor(int i = 0;i < orderList.size();i++) {\n\t\t\t\tincome += orderList.get(i).getOrder_price();\n\t\t\t}\n\t\t\tincomeArr.add(income);\n\t\t}\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\tobj.put(\"income\", incomeArr);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findScheduleByCinemaAndMovie\")\n\t@ResponseBody\n\tpublic JSONObject findScheduleByCinemaAndMovie(@RequestParam(\"cinema_id\")long cinema_id,@RequestParam(\"movie_id\")long movie_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Schedule> list = scheduleService.findScheduleByCineamIdAndMovieId(cinema_id, movie_id);\n\t\tobj.put(\"code\",0);\n\t\tobj.put(\"count\",list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"addSchedule\")\n\t@ResponseBody\n\tpublic JSONObject addSchedule(@RequestParam(\"movie_name\")String movie_name,@RequestParam(\"hall_name\")String hall_name,@RequestParam(\"cinema_name\")String cinema_name,\n\t\t\t@RequestParam(\"schedule_price\")int schedule_price,@RequestParam(\"schedule_startTime\")String schedule_startTime) {\n\t\tJSONObject obj = new JSONObject();\n\t\tSchedule schedule = new Schedule();\n\t\tHall hall = this.hallService.findHallByCinemaAndHallName(cinema_name, hall_name);\n\t\tschedule.setMovie_id(this.movieService.findMovieByName(movie_name).getMovie_id());\n\t\tschedule.setHall_id(hall.getHall_id());\n\t\tschedule.setSchedule_price(schedule_price);\n\t\tschedule.setSchedule_startTime(schedule_startTime);\n\t\tschedule.setSchedule_remain(hall.getHall_capacity());\n\t\tInteger rs = this.scheduleService.addSchedule(schedule);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"mgs\", \"增加成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"mgs\", \"增加失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"updateSchedulePrice\")\n\t@ResponseBody\n\tpublic JSONObject updateSchedulePrice(@RequestParam(\"schedule_id\")long schedule_id,@RequestParam(\"schedule_price\")int schedule_price) {\n\t\tJSONObject obj = new JSONObject();\n\t\tSchedule schedule = new Schedule();\n\t\tschedule.setSchedule_id(schedule_id);\n\t\tschedule.setSchedule_price(schedule_price);\n\t\tInteger rs = this.scheduleService.updateSchedule(schedule);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"mgs\", \"修改成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"mgs\", \"修改失败~\");\n\t\t}\n\t\treturn obj;\n\t} \n\t\n\t@RequestMapping(\"offlineSchedule\")\n\t@ResponseBody\n\tpublic JSONObject offlineSchedule(@RequestParam(\"schedule_id\")long schedule_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tInteger rs = this.scheduleService.deleteSchedule(schedule_id);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"mgs\", \"下架成功~\");\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"mgs\", \"下架失败~\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t\n\t\n\t\n\t/**\n\t * 测试类Api 根据电影id找到所有放映该电影的影院列表\n\t * @param movie_id\n\t * @return\n\t */\n\t@RequestMapping(\"findCinemasByMovieId\")\n\t@ResponseBody\n\tpublic JSONObject findCinemasByMovieId(@RequestParam(\"movie_id\")long movie_id) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<Cinema> list = this.cinemaService.findCinemasByMovieId(movie_id);\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t/**\n\t * 测试专用api\n\t */\n\t@RequestMapping(\"testHall\")\n\t@ResponseBody\n\tpublic JSONObject testHall(@RequestParam(\"hall_name\")String hall_name,@RequestParam(\"cinema_name\")String cinema_name) {\n\t\tHall hall = this.hallService.findHallByCinemaAndHallName(cinema_name, hall_name);\n\t\tJSONObject obj = new JSONObject();\n\t\tobj.put(\"data\", hall);\n\t\treturn obj;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/controller/UserController.java",
    "content": "package com.controller;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpSession;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.entity.User;\nimport com.github.pagehelper.PageInfo;\nimport com.service.IUserService;\nimport com.util.UUIDUtil;\n/**\n * 用户管理模块 \n * update: 2019年7月9日17:18:50 \n * @author Wxj\n */\n@Controller\n@RequestMapping(\"/user\")\npublic class UserController {\n\t//@Autowired\n\t@Resource\n\tprivate IUserService userService;\n\t\n\t@RequestMapping(\"login\")\n\t@ResponseBody\n\tpublic JSONObject login(String user_name,String user_pwd,HttpServletRequest request) {\n\t\tJSONObject obj = new JSONObject();\n\t\tUser user = userService.login(user_name, user_pwd);\n\t\tif(user != null) {\n\t\t\tHttpSession session = request.getSession();\n\t\t\tsession.setAttribute(\"user\", user);\n\t\t\tif(user.getUser_role() == 0) {\n\t\t\t\tobj.put(\"msg\", \"usersuccess\");\n\t\t\t\tobj.put(\"data\", user);\n\t\t\t\treturn obj;\n\t\t\t}else {\n\t\t\t\tobj.put(\"msg\", \"adminsuccess\");\n\t\t\t\tobj.put(\"data\", user);\n\t\t\t\treturn obj;\n\t\t\t}\n\t\t}\n\t\tobj.put(\"msg\", \"fail\");\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"logout\")\n\t@ResponseBody\n\tpublic String logout(HttpServletRequest request) {\n\t\tHttpSession session = request.getSession();\n\t\tsession.removeAttribute(\"user\");\n\t\treturn \"index\";\n\t}\n\t\n\t@RequestMapping(\"register\")\n\t@ResponseBody\n\tpublic String register(User user) {\n\t\tList<User> list = userService.findUserByName(user.getUser_name());\n\t\tif(list.size() > 0) {\n\t\t\treturn \"fail\";\n\t\t}else {\n\t\t\tInteger rs = userService.addUser(user);\n\t\t\tif(rs > 0) {\n\t\t\t\treturn \"success\";\n\t\t\t}else {\n\t\t\t\treturn \"fail\";\n\t\t\t}\n\t\t}\n\t}\n\t\n\t@RequestMapping(\"updateUser\")\n\t@ResponseBody\n\tpublic String updateUser(User user) {\n\t\tInteger rs = userService.updateUserInfo(user);\n\t\tif(rs > 0) {\n\t\t\treturn \"success\";\n\t\t}else {\n\t\t\treturn \"fail\";\n\t\t}\n\t}\n\t\n\t@RequestMapping(\"modifyUserPwd\")\n\t@ResponseBody\n\tpublic String modifyUserPwd(@RequestParam(\"oldPwd\")String oldPwd,@RequestParam(\"newPwd\")String newPwd,HttpServletRequest request) {\n\t\tHttpSession session = request.getSession();\n\t\tUser user = (User)session.getAttribute(\"user\");\n\t\tif(user.getUser_pwd().equals(oldPwd)) {\n\t\t\tuser.setUser_pwd(newPwd);\n\t\t\tuserService.updateUserInfo(user);\n\t\t\tsession.removeAttribute(\"user\");\n\t\t\treturn \"success\";\n\t\t}else {\n\t\t\treturn \"fail\";\n\t\t}\n\t}\n\t\n\t@RequestMapping(\"findAllUser\")\n\t@ResponseBody\n\tpublic JSONObject findAllUser(@RequestParam(value=\"page\",defaultValue=\"1\")Integer page,@RequestParam(value=\"limit\",defaultValue=\"10\")Integer limit,String keyword) {\n\t\tPageInfo<User> info = userService.findAllUserBySplitPage(page, limit, keyword);\n\t\tJSONObject obj = new JSONObject();\n\t\tobj.put(\"msg\", \"\");\n\t\tobj.put(\"code\", 0);\n\t\tobj.put(\"count\", info.getTotal());\n\t\tobj.put(\"data\", info.getList());\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findAllUserInfos\")\n\t@ResponseBody\n\tpublic JSONObject findAllUserInfos() {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<User> list = userService.findAllUserInfos();\n\t\tobj.put(\"msg\",\"\");\n\t\tobj.put(\"code\",0);\n\t\tobj.put(\"count\",list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\t\n\t@RequestMapping(\"findUserInfosByName\")\n\t@ResponseBody\n\tpublic JSONObject findUserInfosByName(@RequestParam(\"user_name\")String user_name) {\n\t\tJSONObject obj = new JSONObject();\n\t\tList<User> list = userService.findUserLikeName(user_name);\n\t\tobj.put(\"msg\",\"\");\n\t\tobj.put(\"code\",0);\n\t\tobj.put(\"count\",list.size());\n\t\tobj.put(\"data\", list);\n\t\treturn obj;\n\t}\n\n\t@RequestMapping(\"/uploadHeadImg\")\n\t@ResponseBody\n\tpublic JSONObject uploadHeadImg(@RequestParam(value=\"file\",required=false) MultipartFile file,User user,HttpServletRequest request) throws IOException {\n\t\tJSONObject obj = new JSONObject();\n\t\tif(file != null) {\n\t\t\tString str = file.getOriginalFilename();\n\t\t\tSystem.out.println(\"file:\"+str);\n\t\t\tString name = UUIDUtil.getUUID() + str.substring(str.lastIndexOf(\".\"));\n\t\t\tSystem.out.println(\"name:\"+name);\n\t\t\tString path = request.getServletContext().getRealPath(\"/upload/head\") + \"/\" + name;\n\t\t\tSystem.out.println(\"path:\"+path);\n\t\t\tString filePath = \"../upload/head/\" + name;\n\t\t\tuser.setUser_headImg(filePath);\n\t\t\tfile.transferTo(new File(path));  \n\t\t\tSystem.out.println(\"文件写入成功,Path:\" + path);\n\t\t}else {\n\t\t\tuser.setUser_headImg(this.userService.findUserById(user.getUser_id()).getUser_headImg());\n\t\t\tuser.setUser_pwd(this.userService.findUserById(user.getUser_id()).getUser_pwd());\n\t\t}\n\t\tInteger rs = userService.updateUserInfo(user);\n\t\tif(rs > 0) {\n\t\t\tobj.put(\"code\", 0);\n\t\t\tobj.put(\"msg\", \"\");\n\t\t\tobj.put(\"data\",user);\n\t\t}else {\n\t\t\tobj.put(\"code\", 200);\n\t\t\tobj.put(\"msg\", \"\");\n\t\t}\n\t\treturn obj;\n\t}\n\t\n\t/**\n\t * 测试Api\n\t * @param file\n\t * @param user_name\n\t * @param request\n\t * @return\n\t */\n\t@RequestMapping(\"test\")\n\t@ResponseBody\n\tpublic JSONObject uploadImg(@RequestParam(value=\"file\",required=false) MultipartFile file,@RequestParam(\"user_name\")String user_name,HttpServletRequest request) {\n\t\tSystem.out.println(file);\n\t\tJSONObject obj = new JSONObject();\n\t\tif(file == null) {\n\t\t\tSystem.out.println(\"null\");\n\t\t}else {\n\t\t\tString str = file.getOriginalFilename();\n\t\t\tSystem.out.println(\"file:\"+str);\n\t\t\tString name = UUIDUtil.getUUID() + str.substring(str.lastIndexOf(\".\"));\n\t\t\tSystem.out.println(\"name:\"+name);\n\t\t\tString path = request.getServletContext().getRealPath(\"/upload/head\") + \"/\" + name;\n\t\t\tSystem.out.println(\"path:\"+path);\n\t\t\tString filePath = \"upload/head/\" + name;\n\t\t\tSystem.out.println(filePath);\n\t\t\ttry {\n\t\t\t\tfile.transferTo(new File(path));\t\n\t\t\t\tSystem.out.println(\"文件写入成功,Path:\" + path);\n\t\t\t}catch(IOException ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t}\n\t\t\tobj.put(\"file\", name);\n\t\t\tobj.put(\"user_name\",user_name);\n\t\t}\n\t\treturn obj;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/entity/Cinema.java",
    "content": "package com.entity;\n\nimport java.util.List;\n\n/**\n * 电影院表实体对象\n * @author Wxj\n */\npublic class Cinema {\n\tprivate long cinema_id;\n\tprivate String cinema_name;    //影院名称\n\tprivate String cinema_address; //影院地址\n\tprivate List<Hall> hallList;   //所有的放映厅集合\n\t\n\tpublic long getCinema_id() {\n\t\treturn cinema_id;\n\t}\n\tpublic void setCinema_id(long cinema_id) {\n\t\tthis.cinema_id = cinema_id;\n\t}\n\tpublic String getCinema_name() {\n\t\treturn cinema_name;\n\t}\n\tpublic void setCinema_name(String cinema_name) {\n\t\tthis.cinema_name = cinema_name;\n\t}\n\tpublic String getCinema_address() {\n\t\treturn cinema_address;\n\t}\n\tpublic void setCinema_address(String cinema_address) {\n\t\tthis.cinema_address = cinema_address;\n\t}\n\tpublic List<Hall> getHallList() {\n\t\treturn hallList;\n\t}\n\tpublic void setHallList(List<Hall> hallList) {\n\t\tthis.hallList = hallList;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/entity/Comment.java",
    "content": "package com.entity;\n/**\n * 评论表实体对象\n * @author Wxj\n */\n\nimport java.util.Date;\n\npublic class Comment {\n\tprivate long comment_id; \n\tprivate long user_id; //所属用户编号\n\tprivate String comment_content; //评论内容\n\tprivate long movie_id; //所属电影编号\n\tprivate Date comment_time; //评论时间\n\tprivate User comment_user; //所属用户\n\t\n\tpublic long getComment_id() {\n\t\treturn comment_id;\n\t}\n\tpublic void setComment_id(long comment_id) {\n\t\tthis.comment_id = comment_id;\n\t}\n\tpublic long getUser_id() {\n\t\treturn user_id;\n\t}\n\tpublic void setUser_id(long user_id) {\n\t\tthis.user_id = user_id;\n\t}\n\tpublic String getComment_content() {\n\t\treturn comment_content;\n\t}\n\tpublic void setComment_content(String comment_content) {\n\t\tthis.comment_content = comment_content;\n\t}\n\tpublic long getMovie_id() {\n\t\treturn movie_id;\n\t}\n\tpublic void setMovie_id(long movie_id) {\n\t\tthis.movie_id = movie_id;\n\t}\n\tpublic Date getComment_time() {\n\t\treturn comment_time;\n\t}\n\tpublic void setComment_time(Date comment_time) {\n\t\tthis.comment_time = comment_time;\n\t}\n\tpublic User getComment_user() {\n\t\treturn comment_user;\n\t}\n\tpublic void setComment_user(User comment_user) {\n\t\tthis.comment_user = comment_user;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/entity/Hall.java",
    "content": "package com.entity;\n\nimport java.util.List;\n\n/**\n * 放映厅表实体对象\n * @author Wxj\n */\npublic class Hall {\n\tprivate long hall_id;\n\tprivate String hall_name;  //放映厅名称\n\tprivate int hall_capacity; //放映厅容量\n\tprivate long cinema_id;  //所属影院编号\n\tprivate Cinema hall_cinema; //所属影院\n\tprivate List<Schedule> ScheduleList; //所有的电影场次集合\n\tpublic long getHall_id() {\n\t\treturn hall_id;\n\t}\n\tpublic void setHall_id(long hall_id) {\n\t\tthis.hall_id = hall_id;\n\t}\n\tpublic List<Schedule> getScheduleList() {\n\t\treturn ScheduleList;\n\t}\n\tpublic void setScheduleList(List<Schedule> scheduleList) {\n\t\tScheduleList = scheduleList;\n\t}\n\tpublic Cinema getHall_cinema() {\n\t\treturn hall_cinema;\n\t}\n\tpublic void setHall_cinema(Cinema hall_cinema) {\n\t\tthis.hall_cinema = hall_cinema;\n\t}\n\tpublic String getHall_name() {\n\t\treturn hall_name;\n\t}\n\tpublic void setHall_name(String hall_name) {\n\t\tthis.hall_name = hall_name;\n\t}\n\tpublic int getHall_capacity() {\n\t\treturn hall_capacity;\n\t}\n\tpublic void setHall_capacity(int hall_capacity) {\n\t\tthis.hall_capacity = hall_capacity;\n\t}\n\tpublic long getCinema_id() {\n\t\treturn cinema_id;\n\t}\n\tpublic void setCinema_id(long cinema_id) {\n\t\tthis.cinema_id = cinema_id;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/entity/Movie.java",
    "content": "package com.entity;\n\nimport java.sql.Date;\t//yyyy-mm-dd\nimport java.util.List; \n/**\n * 电影信息实体对象\n * @author Wxj\n */\npublic class Movie {\n\tprivate long movie_id;\n\tprivate String movie_cn_name;\n\tprivate String movie_fg_name;\n\tprivate String movie_actor;     //演职人员\n\tprivate String movie_director;  //导演\n\tprivate String movie_detail;    //电影详情\n\tprivate String movie_duration;  //电影时长\n\tprivate String movie_type; \t    //电影类型\n\tprivate float movie_score;      //电影评分\n\tprivate float movie_boxOffice;   //票房\n\tprivate long movie_commentCount; //电影参评人数\n\tprivate Date movie_releaseDate;        //上映时间\n\tprivate String movie_country;    //制片地区\n\tprivate String movie_picture;    //电影海报地址\n\tprivate int movie_state; \t\t //电影状态 默认1 1：在线 0：下架\n\tprivate List<Comment> commentList; //所有的评论信息\n\t\n\tpublic long getMovie_id() {\n\t\treturn movie_id;\n\t}\n\tpublic void setMovie_id(long movie_id) {\n\t\tthis.movie_id = movie_id;\n\t}\n\tpublic String getMovie_cn_name() {\n\t\treturn movie_cn_name;\n\t}\n\tpublic int getMovie_state() {\n\t\treturn movie_state;\n\t}\n\tpublic void setMovie_state(int movie_state) {\n\t\tthis.movie_state = movie_state;\n\t}\n\tpublic void setMovie_cn_name(String movie_cn_name) {\n\t\tthis.movie_cn_name = movie_cn_name;\n\t}\n\tpublic String getMovie_fg_name() {\n\t\treturn movie_fg_name;\n\t}\n\tpublic void setMovie_fg_name(String movie_fg_name) {\n\t\tthis.movie_fg_name = movie_fg_name;\n\t}\n\tpublic String getMovie_actor() {\n\t\treturn movie_actor;\n\t}\n\tpublic void setMovie_actor(String movie_actor) {\n\t\tthis.movie_actor = movie_actor;\n\t}\n\tpublic String getMovie_director() {\n\t\treturn movie_director;\n\t}\n\tpublic void setMovie_director(String movie_director) {\n\t\tthis.movie_director = movie_director;\n\t}\n\tpublic String getMovie_detail() {\n\t\treturn movie_detail;\n\t}\n\tpublic void setMovie_detail(String movie_detail) {\n\t\tthis.movie_detail = movie_detail;\n\t}\n\tpublic String getMovie_duration() {\n\t\treturn movie_duration;\n\t}\n\tpublic void setMovie_duration(String movie_duration) {\n\t\tthis.movie_duration = movie_duration;\n\t}\n\tpublic String getMovie_type() {\n\t\treturn movie_type;\n\t}\n\tpublic void setMovie_type(String movie_type) {\n\t\tthis.movie_type = movie_type;\n\t}\n\tpublic float getMovie_score() {\n\t\treturn movie_score;\n\t}\n\tpublic void setMovie_score(float movie_score) {\n\t\tthis.movie_score = movie_score;\n\t}\n\tpublic float getMovie_boxOffice() {\n\t\treturn movie_boxOffice;\n\t}\n\tpublic void setMovie_boxOffice(float movie_boxOffice) {\n\t\tthis.movie_boxOffice = movie_boxOffice;\n\t}\n\tpublic long getMovie_commentCount() {\n\t\treturn movie_commentCount;\n\t}\n\tpublic void setMovie_commentCount(long movie_commentCount) {\n\t\tthis.movie_commentCount = movie_commentCount;\n\t}\n\tpublic Date getReleaseDate() {\n\t\treturn movie_releaseDate;\n\t}\n\tpublic void setReleaseDate(Date releaseDate) {\n\t\tthis.movie_releaseDate = releaseDate;\n\t}\n\tpublic String getMovie_country() {\n\t\treturn movie_country;\n\t}\n\tpublic void setMovie_country(String movie_country) {\n\t\tthis.movie_country = movie_country;\n\t}\n\tpublic String getMovie_picture() {\n\t\treturn movie_picture;\n\t}\n\tpublic void setMovie_picture(String movie_picture) {\n\t\tthis.movie_picture = movie_picture;\n\t}\n\tpublic List<Comment> getCommentList() {\n\t\treturn commentList;\n\t}\n\tpublic void setCommentList(List<Comment> commentList) {\n\t\tthis.commentList = commentList;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/entity/Order.java",
    "content": "package com.entity;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * 订单表实体对象\n * @author Wxj\n *\n */\npublic class Order {\n\tprivate String order_id;\n\tprivate long user_id;   //所属用户编号\n\tprivate long schedule_id;    //所属场次编号,通过schedule_id-》场次信息-》放映厅信息+电影信息\n\tprivate String order_position; //电影票座位信息\n\tprivate int order_state;  //订单状态 0：退票中 -1：无法退票  1：已支付 2：退票成功\n\tprivate int order_price; //订单价格\n\tprivate Date order_time; //订单支付时间\n\tprivate User order_user;   //所属用户对象\n\tprivate Schedule order_schedule; //所属电影场次\n\t\n\tpublic String getOrder_id() {\n\t\treturn order_id;\n\t}\n\tpublic void setOrder_id(String order_id) {\n\t\tthis.order_id = order_id;\n\t}\n\tpublic Date getOrder_time() {\n\t\treturn order_time;\n\t}\n\tpublic void setOrder_time(Date order_time) {\n\t\tthis.order_time = order_time;\n\t}\n\tpublic int getOrder_price() {\n\t\treturn order_price;\n\t}\n\tpublic void setOrder_price(int order_price) {\n\t\tthis.order_price = order_price;\n\t}\n\tpublic long getUser_id() {\n\t\treturn user_id;\n\t}\n\tpublic void setUser_id(long user_id) {\n\t\tthis.user_id = user_id;\n\t}\n\tpublic long getSchedule_id() {\n\t\treturn schedule_id;\n\t}\n\tpublic void setSchedule_id(long schedule_id) {\n\t\tthis.schedule_id = schedule_id;\n\t}\n\tpublic String getOrder_position() {\n\t\treturn order_position;\n\t}\n\tpublic void setOrder_position(String order_position) {\n\t\tthis.order_position = order_position;\n\t}\n\tpublic User getOrder_user() {\n\t\treturn order_user;\n\t}\n\tpublic int getOrder_state() {\n\t\treturn order_state;\n\t}\n\tpublic void setOrder_state(int order_state) {\n\t\tthis.order_state = order_state;\n\t}\n\tpublic void setOrder_user(User order_user) {\n\t\tthis.order_user = order_user;\n\t}\n\tpublic Schedule getOrder_schedule() {\n\t\treturn order_schedule;\n\t}\n\tpublic void setOrder_schedule(Schedule order_schedule) {\n\t\tthis.order_schedule = order_schedule;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/entity/Schedule.java",
    "content": "package com.entity;\n\nimport java.util.Date;\nimport java.util.List;\n\nimport org.springframework.format.annotation.DateTimeFormat;\n\n/**\n * 场次表实体对象\n * @author Wxj\n */\npublic class Schedule {\n\tprivate long schedule_id;\n\tprivate long hall_id;      //所属放映厅\n\tprivate long movie_id;     //放映的电影编号\n\t//@DateTimeFormat(pattern=\"yyyy-MM-dd\")\n\tprivate String schedule_startTime; //电影放映时间\n\tprivate int schedule_price; //售价\n\tprivate int schedule_remain;  //剩余座位数\n\tprivate int schedule_state;   //场次状态 1：上映中 0：下架\n\tprivate Hall schedule_hall; //所属放映厅对象\n\tprivate Movie schedule_movie; //放映的电影\n\tprivate List<Order> orderList; //所有的订单集合\n\t\n\tpublic long getSchedule_id() {\n\t\treturn schedule_id;\n\t}\n\tpublic void setSchedule_id(long schedule_id) {\n\t\tthis.schedule_id = schedule_id;\n\t}\n\tpublic int getSchedule_state() {\n\t\treturn schedule_state;\n\t}\n\tpublic void setSchedule_state(int schedule_state) {\n\t\tthis.schedule_state = schedule_state;\n\t}\n\tpublic Movie getSchedule_movie() {\n\t\treturn schedule_movie;\n\t}\n\tpublic void setSchedule_movie(Movie schedule_movie) {\n\t\tthis.schedule_movie = schedule_movie;\n\t}\n\tpublic long getHall_id() {\n\t\treturn hall_id;\n\t}\n\tpublic void setHall_id(long hall_id) {\n\t\tthis.hall_id = hall_id;\n\t}\n\tpublic long getMovie_id() {\n\t\treturn movie_id;\n\t}\n\tpublic void setMovie_id(long movie_id) {\n\t\tthis.movie_id = movie_id;\n\t}\n\tpublic String getSchedule_startTime() {\n\t\treturn schedule_startTime;\n\t}\n\tpublic void setSchedule_startTime(String schedule_startTime) {\n\t\tthis.schedule_startTime = schedule_startTime;\n\t}\n\tpublic int getSchedule_price() {\n\t\treturn schedule_price;\n\t}\n\tpublic void setSchedule_price(int schedule_price) {\n\t\tthis.schedule_price = schedule_price;\n\t}\n\tpublic int getSchedule_remain() {\n\t\treturn schedule_remain;\n\t}\n\tpublic void setSchedule_remain(int schedule_remain) {\n\t\tthis.schedule_remain = schedule_remain;\n\t}\n\tpublic Hall getSchedule_hall() {\n\t\treturn schedule_hall;\n\t}\n\tpublic void setSchedule_hall(Hall schedule_hall) {\n\t\tthis.schedule_hall = schedule_hall;\n\t}\n\tpublic List<Order> getOrderList() {\n\t\treturn orderList;\n\t}\n\tpublic void setOrderList(List<Order> orderList) {\n\t\tthis.orderList = orderList;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/entity/User.java",
    "content": "package com.entity;\n/**\n * 用户表实体对象\n * @author Wxj\n */\npublic class User {\n\tprivate long user_id;\t      \n\tprivate String user_name; \t  //用户账号\n\tprivate String user_pwd;\t  //用户密码\n\tprivate String user_email;    //用户邮箱\n\tprivate int user_role;    //用户权限 0：普通会员 1：管理员\n\tprivate String user_headImg;  //用户头像地址\n\t\n\tpublic long getUser_id() {\n\t\treturn user_id;\n\t}\n\tpublic void setUser_id(long user_id) {\n\t\tthis.user_id = user_id;\n\t}\n\tpublic String getUser_name() {\n\t\treturn user_name;\n\t}\n\tpublic void setUser_name(String user_name) {\n\t\tthis.user_name = user_name;\n\t}\n\tpublic String getUser_pwd() {\n\t\treturn user_pwd;\n\t}\n\tpublic void setUser_pwd(String user_pwd) {\n\t\tthis.user_pwd = user_pwd;\n\t}\n\tpublic String getUser_email() {\n\t\treturn user_email;\n\t}\n\tpublic void setUser_email(String user_email) {\n\t\tthis.user_email = user_email;\n\t}\n\tpublic int getUser_role() {\n\t\treturn user_role;\n\t}\n\tpublic void setUser_role(int user_role) {\n\t\tthis.user_role = user_role;\n\t}\n\tpublic String getUser_headImg() {\n\t\treturn user_headImg;\n\t}\n\tpublic void setUser_headImg(String user_headImg) {\n\t\tthis.user_headImg = user_headImg;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/CinemaMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.Cinema;\n\n@Repository\npublic interface CinemaMapper {\n\tCinema findCinemaById(long cinema_id);\n\tInteger addCinema(Cinema cinema);\n\tInteger updateCinema(Cinema cinema);\n\tInteger deleteCinema(long cinema_id);\n\tList<Cinema> findAllCinemas();\n\tList<Cinema> findCinemasLikeName(String cinema_name);\n\tList<Cinema> findCinemasByMovieId(long movie_id);\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/CinemaMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.CinemaMapper\">\n\t<resultMap type=\"com.entity.Cinema\" id=\"BaseResultMap\">\n\t\t<id property=\"cinema_id\" column=\"cinema_id\" javaType=\"long\"/>\n\t\t<result property=\"cinema_name\" column=\"cinema_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"cinema_address\" column=\"cinema_address\" javaType=\"java.lang.String\"/>\n\t</resultMap>\n\t\n\t<select id=\"findCinemaById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from cinema where cinema_id = #{cinema_id}\n\t</select>\n\t\n\t<select id=\"findAllCinemas\" resultMap=\"BaseResultMap\">\n\t\tselect * from cinema\n\t</select>\n\t\n\t<select id=\"findCinemasLikeName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from cinema where cinema_name like '%${value}%'\n\t</select>\n\t\n\t<select id=\"findCinemasByMovieId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect distinct cinema.* from hall,schedule,cinema\n\t\twhere hall.hall_id=schedule.hall_id and hall.cinema_id=cinema.cinema_id and schedule.movie_id = #{movie_id}\n\t</select>\n\t\n\t<insert id=\"addCinema\" parameterType=\"com.entity.Cinema\">\n\t\tinsert into cinema(cinema_name,cinema_address)\n\t\tvalues(#{cinema_name},#{cinema_address})\n\t</insert>\n\t\n\t<update id=\"updateCinema\" parameterType=\"com.entity.Cinema\">\n\t\tupdate cinema\n\t\t<set>\n\t\t\tcinema_name = #{cinema_name},\n\t\t\tcinema_address = #{cinema_address}\n\t\t</set>\n\t\twhere cinema_id = #{cinema_id}\n\t</update>\n\t\n\t<delete id=\"deleteCinema\" parameterType=\"long\">\n\t\tdelete from cinema where cinema_id = #{cinema_id}\n\t</delete>\n</mapper>"
  },
  {
    "path": "src/main/java/com/mapper/CommentMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.Comment;\n\n@Repository\npublic interface CommentMapper {\n\t//用户： 修改评论、增加评论\n\t//管理员： 删除评论、 修改评论\n\t//查询用户的评论\n\tComment findCommentById(long comment_id);\n\tInteger addComemnt(Comment comment);\n\tInteger updateComment(Comment comment);\n\tInteger deleteComment(long comment_id);\n\tList<Comment> findAllComments();\n\tList<Comment> findCommentsByMoiveId(long movie_id);\n\tList<Comment> findCommentsByUserName(String user_name);\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/CommentMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.CommentMapper\">\n\t<resultMap type=\"com.entity.Comment\" id=\"BaseResultMap\">\n\t\t<id property=\"comment_id\" column=\"comment_id\" javaType=\"long\"/>\n\t\t<result property=\"comment_content\" column=\"comment_content\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"comment_time\" column=\"comment_time\" javaType=\"java.util.Date\"/>\n\t\t<result property=\"movie_id\" column=\"movie_id\" javaType=\"long\"/>\n\t\t<result property=\"user_id\" column=\"user_id\" javaType=\"long\"/>\n\t</resultMap>\n\t\n\t<select id=\"findCommentById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from comment where comment_id = #{comment_id}\n\t</select>\n\t\n\t<select id=\"findAllComments\" resultMap=\"BaseResultMap\">\n\t\tselect * from comment\n\t</select>\n\t\n\t<select id=\"findCommentsByUserName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect comment.* from comment,user where comment.user_id = user.user_id and user.user_name = #{user_name}\n\t</select>\n\t\n\t<select id=\"findCommentsByMoiveId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from comment where movie_id = #{movie_id}\n\t</select>\n\t\n\t<insert id=\"addComemnt\" parameterType=\"com.entity.Comment\">\n\t\tinsert into comment(comment_content,comment_time,movie_id,user_id)\n\t\tvalues(#{comment_content},#{comment_time},#{movie_id},#{user_id})\n\t</insert>\n\t\n\t<update id=\"updateComment\" parameterType=\"com.entity.Comment\">\n\t\tupdate comment\n\t\t<set>\n\t\t\tcomment_content = #{comment_content},\n\t\t\tcomment_time = #{comment_time},\n\t\t\tmovie_id = #{movie_id},\n\t\t\tuser_id = #{user_id}\n\t\t</set>\n\t\twhere comment_id = #{comment_id}\n\t</update>\n\t\n\t<delete id=\"deleteComment\" parameterType=\"long\">\n\t\tdelete from comment where comment_id = #{comment_id}\n\t</delete>\n\t\n</mapper>"
  },
  {
    "path": "src/main/java/com/mapper/HallMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.Hall;\n\n@Repository\npublic interface HallMapper {\n\tHall findHallById(long hall_id);\n\tHall findHallByCinemaAndHallName(@Param(\"cinema_name\")String cinema_name,@Param(\"hall_name\")String hall_name);\n\tInteger addHall(Hall hall);\n\tInteger updateHall(Hall hall);\n\tInteger deleteHall(long hall_id);\n\tList<Hall> findHallByCinemaId(long cinema_id);\n\tList<Hall> findAllHalls();\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/HallMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.HallMapper\">\n\t<resultMap type=\"com.entity.Hall\" id=\"BaseResultMap\">\n\t\t<id property=\"hall_id\" column=\"hall_id\" javaType=\"long\"/>\n\t\t<result property=\"hall_name\" column=\"hall_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"cinema_id\" column=\"cinema_id\" javaType=\"long\"/>\n\t</resultMap>\n\t\n\t<select id=\"findHallById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from hall where hall_id = #{hall_id}\n\t</select>\n\t\n\t<select id=\"findHallByCinemaAndHallName\" resultMap=\"BaseResultMap\">\n\t\tselect hall.* from hall,cinema where hall.cinema_id = cinema.cinema_id \n\t\tand cinema_name = #{cinema_name} and hall_name= #{hall_name}\n\t</select>\n\t\t\n\t<select id=\"findHallByCinemaId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from hall where cinema_id = #{cinema_id}\n\t</select>\n\t\n\t<select id=\"findAllHalls\" resultMap=\"BaseResultMap\">\n\t\tselect * from hall\n\t</select>\n\t\n\t<insert id=\"addHall\" parameterType=\"com.entity.Hall\">\n\t\tinsert into hall(hall_name,movie_id)\n\t\tvalues(hall_name,movie_id)\n\t</insert>\n\t\n\t<update id=\"updateHall\" parameterType=\"com.entity.Hall\">\n\t\tupdate hall\n\t\t<set>\n\t\t\thall_name = #{hall_name},\n\t\t\tmovie_id = #{movie_id}\n\t\t</set>\n\t\twhere hall_id = #{hall_id}\n\t</update>\n\t\n\t<delete id=\"deleteHall\" parameterType=\"long\">\n\t\tdelete from hall where hall_id = #{hall_id}\n\t</delete>\n</mapper>"
  },
  {
    "path": "src/main/java/com/mapper/MovieMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.Movie;\n\n@Repository\npublic interface MovieMapper {\n\tMovie findMovieById(long movie_id);\n\tMovie findMovieByName(String movie_cn_name);\n\tInteger addMovie(Movie movie);\n\tInteger deleteMovie(long movie_id);\n\tInteger updateMovie(Movie movie);\n\tInteger deleteMovieCommentCount(long movie_id);\n\tInteger addMovieCommentCount(long movie_id);\n\tInteger changeMovieBoxOffice(@Param(\"movie_boxOffice\")float movie_boxOffice,@Param(\"movie_id\")long movie_id);\n\tList<Movie> findAllMovies(int movie_state);\n\tList<Movie> findMoviesLikeName(String name);\n\tList<Movie> findMoviesLikeType(String type);\n\t//上映时间  参评人数  评分\n\tList<Movie> sortMovieByDate();\n\tList<Movie> sortMovieByCount();\n\tList<Movie> sortMovieByScore();\n\t//票房排序\n\tList<Movie> sortMovieByBoxOffice();\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/MovieMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.MovieMapper\">\n\t<resultMap type=\"com.entity.Movie\" id=\"BaseResultMap\">\n\t\t<id property=\"movie_id\" column=\"movie_id\" javaType=\"long\"/>\n\t\t<result property=\"movie_actor\" column=\"movie_actor\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_boxOffice\" column=\"movie_boxOffice\" javaType=\"float\"/>  \n\t\t<result property=\"movie_cn_name\" column=\"movie_cn_name\" javaType=\"java.lang.String\"/>  \n\t\t<result property=\"movie_commentCount\" column=\"movie_commentCount\" javaType=\"long\"/>  \n\t\t<result property=\"movie_country\" column=\"movie_country\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_detail\" column=\"movie_detail\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_director\" column=\"movie_director\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_duration\" column=\"movie_duration\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_fg_name\" column=\"movie_fg_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_picture\" column=\"movie_picture\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_score\" column=\"movie_score\" javaType=\"float\"/>\n\t\t<result property=\"movie_type\" column=\"movie_type\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_releaseDate\" column=\"movie_releaseDate\" javaType=\"java.sql.Date\"/>\n\t\t<result property=\"movie_state\" column=\"movie_state\" javaType=\"java.lang.Integer\"/>\n\t</resultMap>\n\t\n\t<select id=\"findMovieById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_id = #{movie_id}\n\t</select>\n\t\n\t<select id=\"findMovieByName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_cn_name = #{movie_cn_name}\n\t</select>\n\t\n\t<insert id=\"addMovie\" parameterType=\"com.entity.Movie\">\n\t\tinsert into movie(movie_cn_name,movie_fg_name,movie_actor,movie_director,movie_detail,movie_duration,movie_type,movie_score,movie_releaseDate,movie_country,movie_picture)\n\t\tvalues(#{movie_cn_name},#{movie_fg_name},#{movie_actor},#{movie_director},#{movie_detail},#{movie_duration},#{movie_type},#{movie_score},#{movie_releaseDate},#{movie_country},#{movie_picture})\n\t</insert>\n\t\n\t<update id=\"deleteMovie\" parameterType=\"long\">\n\t\tupdate movie\n\t\t<set>\n\t\t\tmovie_state = 0\n\t\t</set>\n\t\twhere movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"changeMovieBoxOffice\">\n\t\tupdate movie set movie_boxOffice = movie_boxOffice + #{movie_boxOffice} where movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"updateMovie\" parameterType=\"com.entity.Movie\">\n\t\tupdate movie\n\t\t<set>\n\t\t\tmovie_cn_name = #{movie_cn_name},\n\t\t\tmovie_fg_name = #{movie_fg_name},\n\t\t\tmovie_actor = #{movie_actor},\n\t\t\tmovie_director = #{movie_director},\n\t\t\tmovie_detail = #{movie_detail},\n\t\t\tmovie_duration = #{movie_duration},\n\t\t\tmovie_type = #{movie_type},\n\t\t\tmovie_country = #{movie_country},\n\t\t\tmovie_picture = #{movie_picture}\n\t\t</set>\n\t\twhere movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"deleteMovieCommentCount\" parameterType=\"long\">\n\t\tupdate movie set movie_commentCount = movie_commentCount -1 where movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"addMovieCommentCount\" parameterType=\"long\">\n\t\tupdate movie set movie_commentCount = movie_commentCount +1 where movie_id = #{movie_id}\n\t</update>\n\t\n\t<select id=\"findAllMovies\" parameterType=\"java.lang.Integer\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = #{movie_state}\n\t</select>\n\t\n\t<select id=\"findMoviesLikeName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_cn_name like '%${value}%' and movie_state = 1\n\t</select>\n\t\n\t<select id=\"findMoviesLikeType\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_type like '%${value}%' and movie_state = 1\n\t</select>\n\t\n\t<select id=\"sortMovieByDate\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1  order by movie_releaseDate DESC\n\t</select>\n\t\n\t<select id=\"sortMovieByCount\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1 order by movie_commentCount DESC\n\t</select>\n\t\n\t<select id=\"sortMovieByScore\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1 order by movie_score DESC\n\t</select>\n\t\n\t<select id=\"sortMovieByBoxOffice\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1 order by movie_boxOffice desc\n\t</select>\n\t\n</mapper>"
  },
  {
    "path": "src/main/java/com/mapper/OrderMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.Order;\n\n@Repository\npublic interface OrderMapper {\n\tOrder findOrderById(String order_id);\n\tInteger addOrder(Order order);\n\tInteger updateOrderStateToRefund(String order_id); //申请退票\n\tInteger updateOrderStateToRefunded(String order_id); //同意退票\n\tList<Order> findRefundOrderByUserName(String user_name);\n\tList<Order> findOrdersByUserName(String user_name);\n\tList<Order> findAllOrders();\n\tList<Order> findOrdersByScheduleId(long schedule_id);\n\tList<Order> findOrdersByState(int order_state);\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/OrderMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.OrderMapper\">\n\t<resultMap type=\"com.entity.Order\" id=\"BaseResultMap\">\n\t\t<id property=\"order_id\" column=\"order_id\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"order_position\" column=\"order_position\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"order_state\" column=\"order_state\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"schedule_id\" column=\"schedule_id\" javaType=\"long\"/>\n\t\t<result property=\"user_id\" column=\"user_id\" javaType=\"long\"/>\n\t\t<result property=\"order_price\" column=\"order_price\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"order_time\" column=\"order_time\" javaType=\"java.util.Date\"/>\n\t</resultMap>\n\t\n\t<select id=\"findOrderById\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo where order_id = #{order_id}\n\t</select>\n\t\n\t<select id=\"findAllOrders\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo order by order_time desc\n\t</select>\n\t\n\t\n\t<select id=\"findOrdersByScheduleId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo where schedule_id = #{schedule_id} and order_state != 2 order by order_time desc\n\t</select>\n\t\n\t<select id=\"findOrdersByState\" parameterType=\"int\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo where order_state = #{order_state} order by order_time desc\n\t</select>\n\t\n\t<select id=\"findOrdersByUserName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect orderinfo.*  from orderinfo,user where orderinfo.user_id = user.user_id and user.user_name = #{user_name} order by order_time desc\n\t</select>\n\t\n\t<select id=\"findRefundOrderByUserName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect orderinfo.*  from orderinfo,user where orderinfo.user_id = user.user_id and user.user_name = #{user_name} and orderinfo.order_state = 0 order by order_time desc\n\t</select>\n\t<insert id=\"addOrder\" parameterType=\"com.entity.Order\">\n\t\tinsert into orderinfo(order_id,order_position,schedule_id,user_id,order_price,order_time)\n\t\tvalues(#{order_id},#{order_position},#{schedule_id},#{user_id},#{order_price},#{order_time})\n\t</insert>\n\t\n\t<update id=\"updateOrderStateToRefund\" parameterType=\"java.lang.String\">\n\t\tupdate orderinfo set order_state = 0 where order_id = #{order_id}\n\t</update>\n\t\n\t<update id=\"updateOrderStateToRefunded\" parameterType=\"java.lang.String\">\n\t\tupdate orderinfo set order_state = 2 where order_id = #{order_id}\n\t</update>\n</mapper>"
  },
  {
    "path": "src/main/java/com/mapper/ScheduleMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.Schedule;\n\n@Repository\npublic interface ScheduleMapper {\n\tSchedule findScheduleById(long schedule_id);\n\tInteger addSchedule(Schedule schedule);\n\tInteger updateSchedule(Schedule schedule);\n\tInteger deleteSchedule(long schedule_id);\n\tInteger addScheduleRemain(long schedule_id);\n\tInteger delScheduleRemain(long schedule_id);\n\tList<Schedule> findScheduleByMovieName(String movie_name);\n\tList<Schedule> findOffScheduleByMovieName(String movie_name);\n\tList<Schedule> findScheduleByState(int schedule_state);\n\tList<Schedule> findAllSchedule();\n\tList<Schedule> findScheduleByCinemaAndMovie(@Param(\"cinema_id\")long cinema_id,@Param(\"movie_id\")long movie_id);\n\tList<Schedule> findScheduleByCinemaAndMovieAndHall(@Param(\"hall_id\")long hall_id,@Param(\"cinema_id\")long cinema_id,@Param(\"movie_id\")long movie_id);\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/ScheduleMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.ScheduleMapper\">\n\t<resultMap type=\"com.entity.Schedule\" id=\"BaseResultMap\">\n\t\t<id property=\"schedule_id\" column=\"schedule_id\" javaType=\"long\"/>\n\t\t<result property=\"hall_id\" column=\"hall_id\" javaType=\"long\"/>\n\t\t<result property=\"movie_id\" column=\"movie_id\" javaType=\"long\"/>\n\t\t<result property=\"schedule_price\" column=\"schedule_price\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"schedule_remain\" column=\"schedule_remain\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"schedule_startTime\" column=\"schedule_startTime\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"schedule_state\" column=\"schedule_state\" javaType=\"java.lang.Integer\"/>\n\t</resultMap>\n\t\n\t<select id=\"findScheduleById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from schedule where schedule_id = #{schedule_id}\n\t</select>\n\t\n\t<select id=\"findScheduleByState\" parameterType=\"java.lang.Integer\" resultMap=\"BaseResultMap\">\n\t\tselect * from schedule where schedule_state = #{schedule_state}\n\t</select>\n\t\n\t<select id=\"findScheduleByCinemaAndMovie\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,hall where schedule.hall_id=hall.hall_id\n\t\t and hall.cinema_id = #{cinema_id} and movie_id = #{movie_id} and schedule_state = 1\n\t</select>\n\t\n\t<select id=\"findScheduleByCinemaAndMovieAndHall\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,hall where schedule.hall_id=hall.hall_id\n\t\t and hall.cinema_id = #{cinema_id} and movie_id = #{movie_id} and schedule.hall_id = #{hall_id} and schedule_state = 1\n\t</select>\n\t\n\t<select id=\"findAllSchedule\" resultMap=\"BaseResultMap\">\n\t\tselect * from schedule\n\t</select>\n\t\n\t<select id=\"findScheduleByMovieName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,movie\n\t\twhere schedule.movie_id = movie.movie_id and schedule.schedule_state = 1 and movie.movie_cn_name like '%${value}%'\n\t</select>\n\t\n\t<select id=\"findOffScheduleByMovieName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,movie\n\t\twhere schedule.movie_id = movie.movie_id and schedule.schedule_state = 0 and movie.movie_cn_name like '%${value}%'\n\t</select>\n\t\n\t<insert id=\"addSchedule\" parameterType=\"com.entity.Schedule\">\n\t\tinsert into schedule(hall_id,movie_id,schedule_price,schedule_remain,schedule_startTime)\n\t\tvalues(#{hall_id},#{movie_id},#{schedule_price},#{schedule_remain},#{schedule_startTime})\n\t</insert>\n\t\n\t<update id=\"updateSchedule\" parameterType=\"com.entity.Schedule\">\n\t\tupdate schedule\n\t\t<set>\n\t\t\tschedule_price = #{schedule_price}\n\t\t</set>\n\t\twhere schedule_id = #{schedule_id}\n\t</update>\n\t\n\t<update id=\"deleteSchedule\" parameterType=\"long\">\n\t\tupdate schedule set schedule_state = 0 where schedule_id = #{schedule_id}\n\t</update>\n\t\n\t<update id=\"addScheduleRemain\" parameterType=\"long\">\n\t\tupdate schedule set schedule_remain = schedule_remain + 1 where schedule_id = #{schedule_id}\n\t</update>\n\t\n\t<update id=\"delScheduleRemain\" parameterType=\"long\">\n\t\tupdate schedule set schedule_remain = schedule_remain - 1 where schedule_id = #{schedule_id}\n\t</update>\n</mapper>"
  },
  {
    "path": "src/main/java/com/mapper/UserMapper.java",
    "content": "package com.mapper;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.entity.User;\n@Repository\npublic interface UserMapper {\n\tUser findUserById(long user_id);\n\tInteger addUser(User user);\n\tInteger deleteUser(long user_id);\n\tInteger updateUser(User user);\n\tList<User> findAllUser();\n\tList<User> findUserByName(String name);\n\tList<User> findUserLikeName(String name);\n}\n"
  },
  {
    "path": "src/main/java/com/mapper/UserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.UserMapper\">\n\t<resultMap type=\"com.entity.User\" id=\"BaseResultMap\">\n\t\t<id property=\"user_id\" column=\"user_id\" javaType=\"long\"/>\n\t\t<result property=\"user_name\" column=\"user_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"user_pwd\" column=\"user_pwd\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"user_email\" column=\"user_email\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"user_role\" column=\"user_role\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"user_headImg\" column=\"user_headImg\" javaType=\"java.lang.String\"/>\n\t</resultMap>\n\t<select id=\"findUserById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from user where user_id = #{id}\n\t</select>\n\t<select id=\"findAllUser\" resultMap=\"BaseResultMap\">\n\t\tselect * from user\n\t</select>\n\t<select id=\"findUserByName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from user where user_name = #{name}\n\t</select>\n\t<select id=\"findUserLikeName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from user where user_name like '%${value}%'\n\t</select>\n\t<insert id=\"addUser\" parameterType=\"com.entity.User\">\n\t\tinsert into user(user_name,user_pwd,user_email)\n\t\tvalues(#{user_name},#{user_pwd},#{user_email})\n\t</insert>\n\t<update id=\"updateUser\" parameterType=\"com.entity.User\">\n\t\tupdate user \n\t\t<set>\n\t\t\t<if test=\"user_name!=null\">\n\t\t\t\tuser_name = #{user_name},\n\t\t\t</if>\n\t\t\t<if test=\"user_pwd!=null\">\n\t\t\t\tuser_pwd = #{user_pwd},\n\t\t\t</if>\n\t\t\t\tuser_email = #{user_email},\n\t\t\t\tuser_headImg = #{user_headImg}\n\t\t</set>\n\t\twhere user_id = #{user_id}\n\t</update>\n</mapper>"
  },
  {
    "path": "src/main/java/com/service/ICinemaService.java",
    "content": "package com.service;\n\nimport java.util.List;\n\nimport com.entity.Cinema;\n\npublic interface ICinemaService {\n\tCinema findCinemaById(long cinema_id);\n\tInteger addCinema(Cinema cinema);\n\tInteger updateCinema(Cinema cinema);\n\tInteger deleteCinema(long cinema_id);\n\tList<Cinema> findAllCinemas();\n\tList<Cinema> findCinemasLikeName(String cinema_name);\n\tList<Cinema> findCinemasByMovieId(long movie_id);\n}\n"
  },
  {
    "path": "src/main/java/com/service/ICommentService.java",
    "content": "package com.service;\n\nimport java.util.List;\n\nimport com.entity.Comment;\nimport com.github.pagehelper.PageInfo;\n\npublic interface ICommentService {\n\tComment findCommentById(long comment_id);\n\tInteger addComemnt(Comment comment);\n\tInteger updateComment(Comment comment);\n\tInteger deleteComment(long comment_id);\n\tList<Comment> findAllComments();\n\tList<Comment> findCommentsByMovieId(long movie_id);\n\tPageInfo<Comment> findAllCommentsBySplitPage(Integer page,Integer limit,String keyword);\n\tPageInfo<Comment> findCommentsByUserName(Integer page,Integer limit,String user_name);\n}\n"
  },
  {
    "path": "src/main/java/com/service/IHallService.java",
    "content": "package com.service;\n\nimport java.util.List;\n\nimport com.entity.Hall;\n\npublic interface IHallService {\n\tHall findHallById(long hall_id);\n\tHall findHallByCinemaAndHallName(String cinema_name,String hall_name);\n\tInteger addHall(Hall hall);\n\tInteger updateHall(Hall hall);\n\tInteger deleteHall(long hall_id);\n\tList<Hall> findHallByCinemaId(long cinema_id);\n\tList<Hall> findAllHalls();\n}\n"
  },
  {
    "path": "src/main/java/com/service/IMovieService.java",
    "content": "package com.service;\n\nimport java.util.List;\n\nimport com.entity.Movie;\n\npublic interface IMovieService {\n\tMovie findMovieById(long movie_id);\n\tMovie findMovieByName(String movie_cn_name);\n\tInteger addMovie(Movie movie);\n\tInteger deleteMovie(long movie_id);\n\tInteger updateMovie(Movie movie);\n\tInteger delCommentCount(long movie_id);\n\tInteger changeMovieBoxOffice(float price,long movie_id);\n\tInteger addCommentCount(long movie_id);\n\tList<Movie> findAllMovies(int movie_state);\n\tList<Movie> findMoviesLikeName(String name);\n\tList<Movie> findMoviesLikeType(String type);\n\t//上映时间  参评人数  评分\n\tList<Movie> sortMovieByDate();\n\tList<Movie> sortMovieByCount();\n\tList<Movie> sortMovieByScore();\n\tList<Movie> sortMovieByBoxOffice();\n}\n"
  },
  {
    "path": "src/main/java/com/service/IOrderService.java",
    "content": "package com.service;\n\nimport java.util.List;\n\nimport com.entity.Order;\nimport com.github.pagehelper.PageInfo;\n\npublic interface IOrderService {\n\tOrder findOrderById(String order_id);\n\tInteger addOrder(Order order);\n\tInteger updateOrderStateToRefund(String order_id); //申请退票\n\tInteger updateOrderStateToRefunded(String order_id); //同意退票\n\tPageInfo<Order> findOrdersByUserName(Integer page,Integer limit,String user_name);\n\tList<Order> findAllOrders();\n\tList<Order> findRefundOrderByUserName(String user_name);\n\tPageInfo<Order> findOrdersByState(Integer page,Integer limit,int order_state);\n\tPageInfo<Order> findAllOrdersBySplitPage(Integer page,Integer limit,String keyword);\n}\n"
  },
  {
    "path": "src/main/java/com/service/IScheduleService.java",
    "content": "package com.service;\n\nimport java.util.List;\n\nimport com.entity.Schedule;\nimport com.github.pagehelper.PageInfo;\n\npublic interface IScheduleService {\n\tSchedule findScheduleById(long schedule_id);\n\tInteger addSchedule(Schedule schedule);\n\tInteger updateSchedule(Schedule schedule);\n\tInteger deleteSchedule(long schedule_id);\n\tInteger addScheduleRemain(long schedule_id);\n\tInteger delScheduleRemain(long schedule_id);\n\tPageInfo<Schedule> findScheduleByMovieName(Integer page,Integer limit,String movie_name);\n\tPageInfo<Schedule> findOffScheduleByMovieName(Integer page,Integer limit,String movie_name);\n\tPageInfo<Schedule> findAllSchedule(Integer page,Integer limit);\n\tPageInfo<Schedule> findAllScheduleByState(Integer page,Integer limit,int schedule_state);\n\tList<Schedule> findScheduleByCinemaAndMovie(long cinema_id,long movie_id);\n\tList<Schedule> findScheduleByCineamIdAndMovieId(long cinema_id,long movie_id);\n}\n"
  },
  {
    "path": "src/main/java/com/service/IUserService.java",
    "content": "package com.service;\n\n\nimport java.util.List;\n\nimport com.entity.User;\nimport com.github.pagehelper.PageInfo;\n\npublic interface IUserService {\n\tUser login(String user_name,String user_pwd);\n\tInteger updateUserInfo(User user);\n\tUser findUserById(long user_id);\n\tList<User> findUserByName(String name);\n\tList<User> findUserLikeName(String name);\n\tInteger addUser(User user);\n\tInteger deleteUser(long user_id);\n\tList<User> findAllUserInfos();\n\tPageInfo<User> findAllUserBySplitPage(Integer page,Integer limit,String keyword);\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/CinemaServiceImp.java",
    "content": "package com.service.imp;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.Cinema;\nimport com.entity.Hall;\nimport com.entity.Schedule;\nimport com.mapper.CinemaMapper;\nimport com.mapper.HallMapper;\nimport com.mapper.ScheduleMapper;\nimport com.service.ICinemaService;\n\n@Service\npublic class CinemaServiceImp implements ICinemaService{\n\t@Autowired\n\tprivate CinemaMapper cinemaMapper;\n\t@Autowired\n\tprivate HallMapper hallMapper;\n\t@Autowired\n\tprivate ScheduleMapper scheduleMapper;\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Cinema findCinemaById(long cinema_id) {\n\t\tCinema cinema = this.cinemaMapper.findCinemaById(cinema_id);\n\t\tList<Hall> list = this.hallMapper.findHallByCinemaId(cinema_id);\n\t\tcinema.setHallList(list);\n\t\treturn cinema;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Cinema> findCinemasByMovieId(long movie_id) {\n\t\tList<Cinema> cinemaList = this.cinemaMapper.findCinemasByMovieId(movie_id);\n\t\tfor(Cinema cinema : cinemaList) {\n\t\t\tList<Hall> hallList = this.hallMapper.findHallByCinemaId(cinema.getCinema_id());\n\t\t\tfor(Hall hall : hallList) {\n\t\t\t\thall.setScheduleList(this.scheduleMapper.findScheduleByCinemaAndMovieAndHall(hall.getHall_id(), hall.getCinema_id(), movie_id));\n\t\t\t}\n\t\t\tcinema.setHallList(hallList);\n\t\t}\n\t\treturn cinemaList;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addCinema(Cinema cinema) {\n\t\treturn this.cinemaMapper.addCinema(cinema);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateCinema(Cinema cinema) {\n\t\treturn this.cinemaMapper.updateCinema(cinema);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer deleteCinema(long cinema_id) {\n\t\treturn this.cinemaMapper.deleteCinema(cinema_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Cinema> findAllCinemas() {\n\t\tList<Cinema> list = this.cinemaMapper.findAllCinemas();\n\t\tfor(Cinema cinema : list) {\n\t\t\tList<Hall> hallList = this.hallMapper.findHallByCinemaId(cinema.getCinema_id());\n\t\t\tcinema.setHallList(hallList);\n\t\t}\n\t\treturn list;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Cinema> findCinemasLikeName(String cinema_name) {\n\t\tList<Cinema> list = this.cinemaMapper.findCinemasLikeName(cinema_name);\n\t\tfor(Cinema cinema : list) {\n\t\t\tList<Hall> hallList = this.hallMapper.findHallByCinemaId(cinema.getCinema_id());\n\t\t\tcinema.setHallList(hallList);\n\t\t}\n\t\treturn list;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/CommentServiceImp.java",
    "content": "package com.service.imp;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.Comment;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.mapper.CommentMapper;\nimport com.service.ICommentService;\n\n@Service\npublic class CommentServiceImp implements ICommentService{\n\n\t@Autowired\n\tprivate CommentMapper commentMapper;\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Comment findCommentById(long comment_id) {\n\t\treturn this.commentMapper.findCommentById(comment_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addComemnt(Comment comment) {\n\t\treturn this.commentMapper.addComemnt(comment);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateComment(Comment comment) {\n\t\treturn this.commentMapper.updateComment(comment);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer deleteComment(long comment_id) {\n\t\treturn this.commentMapper.deleteComment(comment_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Comment> findAllComments() {\n\t\treturn this.commentMapper.findAllComments();\n\t}\n\t\n\t\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Comment> findAllCommentsBySplitPage(Integer page, Integer limit, String keyword) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Comment> list = new ArrayList<Comment>();\n\t\tif(keyword != null && !keyword.trim().equals(\"\")) {\n\t\t\tSystem.out.println(\"keyword:\"+keyword);\n\t\t\tlist = this.commentMapper.findCommentsByUserName(keyword);\n\t\t}else {\n\t\t\t//System.out.println(\"keyword:\"+keyword);\n\t\t\tlist = this.commentMapper.findAllComments();\n\t\t}\n\t\tPageInfo<Comment> info = new PageInfo<Comment>(list);\n\t\treturn info;\n\t}\n\t\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Comment> findCommentsByUserName(Integer page, Integer limit,String user_name) {\n\t\tPageHelper.startPage(page,limit);\n\t\tList<Comment> list = new ArrayList<Comment>();\n\t\tlist = this.commentMapper.findCommentsByUserName(user_name);\n\t\tPageInfo<Comment> info = new PageInfo<Comment>(list);\n\t\treturn info;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Comment> findCommentsByMovieId(long movie_id) {\n\t\treturn this.commentMapper.findCommentsByMoiveId(movie_id);\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/HallServiceImp.java",
    "content": "package com.service.imp;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.Hall;\nimport com.mapper.CinemaMapper;\nimport com.mapper.HallMapper;\nimport com.service.IHallService;\n\n@Service\npublic class HallServiceImp implements IHallService{\n\t@Autowired\n\tprivate HallMapper hallMapper;\n\t@Autowired\n\tprivate CinemaMapper cinemaMapper;\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Hall findHallById(long hall_id) {\n\t\tHall hall = this.hallMapper.findHallById(hall_id);\n\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\treturn hall;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Hall findHallByCinemaAndHallName(String cinema_name, String hall_name) {\n\t\treturn this.hallMapper.findHallByCinemaAndHallName(cinema_name, hall_name);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addHall(Hall hall) {\n\t\treturn this.hallMapper.addHall(hall);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateHall(Hall hall) {\n\t\treturn this.hallMapper.updateHall(hall);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer deleteHall(long hall_id) {\n\t\treturn this.hallMapper.deleteHall(hall_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Hall> findHallByCinemaId(long cinema_id) {\n\t\tList<Hall> list = this.hallMapper.findHallByCinemaId(cinema_id);\n\t\tfor(Hall hall : list) {\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t}\n\t\treturn list;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Hall> findAllHalls() {\n\t\tList<Hall> list = this.hallMapper.findAllHalls();\n\t\tfor(Hall hall : list) {\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t}\n\t\treturn list;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/MovieServiceImp.java",
    "content": "package com.service.imp;\t\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.Comment;\nimport com.entity.Movie;\nimport com.mapper.CommentMapper;\nimport com.mapper.MovieMapper;\nimport com.mapper.UserMapper;\nimport com.service.IMovieService;\n\n@Service\npublic class MovieServiceImp implements IMovieService{\n\t@Autowired\n\tprivate MovieMapper movieMapper;\n\t@Autowired\n\tprivate CommentMapper commentMapper;\n\t@Autowired\n\tprivate UserMapper userMapper;\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Movie findMovieById(long movie_id) {\n\t\tMovie movie = this.movieMapper.findMovieById(movie_id);\n\t\tList<Comment> list = this.commentMapper.findCommentsByMoiveId(movie_id);\n\t\tfor(Comment comment : list) {\n\t\t\tcomment.setComment_user(this.userMapper.findUserById(comment.getUser_id()));\n\t\t}\n\t\tmovie.setCommentList(list);\n\t\treturn movie;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer changeMovieBoxOffice(float price, long movie_id) {\n\t\treturn this.movieMapper.changeMovieBoxOffice(price, movie_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Movie findMovieByName(String movie_cn_name) {\n\t\treturn this.movieMapper.findMovieByName(movie_cn_name);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addCommentCount(long movie_id) {\n\t\treturn this.movieMapper.addMovieCommentCount(movie_id);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer delCommentCount(long movie_id) {\n\t\treturn this.movieMapper.deleteMovieCommentCount(movie_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addMovie(Movie movie) {\n\t\treturn this.movieMapper.addMovie(movie);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer deleteMovie(long movie_id) {\n\t\treturn this.movieMapper.deleteMovie(movie_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateMovie(Movie movie) {\n\t\treturn this.movieMapper.updateMovie(movie);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> findAllMovies(int movie_state) {\n\t\treturn this.movieMapper.findAllMovies(movie_state);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> findMoviesLikeName(String name) {\n\t\treturn this.movieMapper.findMoviesLikeName(name);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> findMoviesLikeType(String type) {\n\t\treturn this.movieMapper.findMoviesLikeType(type);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> sortMovieByDate() {\n\t\treturn this.movieMapper.sortMovieByDate();\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> sortMovieByCount() {\n\t\treturn this.movieMapper.sortMovieByCount();\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> sortMovieByScore() {\n\t\treturn this.movieMapper.sortMovieByScore();\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Movie> sortMovieByBoxOffice() {\n\t\treturn this.movieMapper.sortMovieByBoxOffice();\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/OrderServiceImp.java",
    "content": "package com.service.imp;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.Hall;\nimport com.entity.Order;\nimport com.entity.Schedule;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.mapper.CinemaMapper;\nimport com.mapper.HallMapper;\nimport com.mapper.MovieMapper;\nimport com.mapper.OrderMapper;\nimport com.mapper.ScheduleMapper;\nimport com.mapper.UserMapper;\nimport com.service.IOrderService;\n\n@Service\npublic class OrderServiceImp implements IOrderService{\n\t@Autowired\n\tprivate OrderMapper orderMapper;\n\t@Autowired\n\tprivate UserMapper userMapper;\n\t@Autowired\n\tprivate ScheduleMapper scheduleMapper;\n\t@Autowired\n\tprivate HallMapper hallMapper;\n\t@Autowired\n\tprivate MovieMapper movieMapper;\n\t@Autowired\n\tprivate CinemaMapper cinemaMapper;\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Order findOrderById(String order_id) {\n\t\tOrder order = this.orderMapper.findOrderById(order_id);\n\t\tif(order != null) {\n\t\t\torder.setOrder_user(this.userMapper.findUserById(order.getUser_id()));\n\t\t\tSchedule schedule = this.scheduleMapper.findScheduleById(order.getSchedule_id());\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\torder.setOrder_schedule(schedule);\n\t\t}else {\n\t\t\torder = null;\n\t\t}\n\t\treturn order;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Order> findRefundOrderByUserName(String user_name) {\n\t\tList<Order> list = this.orderMapper.findRefundOrderByUserName(user_name);\n\t\tif(list.size() > 0) {\n\t\t\tfor(Order order : list) {\n\t\t\t\torder.setOrder_user(this.userMapper.findUserById(order.getUser_id()));\n\t\t\t\tSchedule schedule = this.scheduleMapper.findScheduleById(order.getSchedule_id());\n\t\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\t\tschedule.setSchedule_hall(hall);\n\t\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\t\torder.setOrder_schedule(schedule);\n\t\t\t}\n\t\t}else {\n\t\t\tlist = null;\n\t\t}\n\t\treturn list;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addOrder(Order order) {\n\t\treturn this.orderMapper.addOrder(order);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateOrderStateToRefund(String order_id) {\n\t\treturn this.orderMapper.updateOrderStateToRefund(order_id);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateOrderStateToRefunded(String order_id) {\n\t\treturn this.orderMapper.updateOrderStateToRefunded(order_id);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Order> findOrdersByUserName(Integer page,Integer limit,String user_name) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Order> list = this.orderMapper.findOrdersByUserName(user_name);\n\t\tfor(Order order : list) {\n\t\t\torder.setOrder_user(this.userMapper.findUserById(order.getUser_id()));\n\t\t\tSchedule schedule = this.scheduleMapper.findScheduleById(order.getSchedule_id());\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\torder.setOrder_schedule(schedule);\n\t\t}\n\t\tPageInfo<Order> info = new PageInfo<Order>(list);\n\t\treturn info;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Order> findAllOrders() {\n\t\tList<Order> list = this.orderMapper.findAllOrders();\n\t\tfor(Order order : list) {\n\t\t\torder.setOrder_user(this.userMapper.findUserById(order.getUser_id()));\n\t\t\tSchedule schedule = this.scheduleMapper.findScheduleById(order.getSchedule_id());\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\torder.setOrder_schedule(schedule);\n\t\t}\n\t\treturn list;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Order> findOrdersByState(Integer page,Integer limit,int order_state) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Order> list = this.orderMapper.findOrdersByState(order_state);\n\t\tfor(Order order : list) {\n\t\t\torder.setOrder_user(this.userMapper.findUserById(order.getUser_id()));\n\t\t\tSchedule schedule = this.scheduleMapper.findScheduleById(order.getSchedule_id());\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\torder.setOrder_schedule(schedule);\n\t\t}\n\t\tPageInfo<Order> info = new PageInfo<Order>(list);\n\t\treturn info;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Order> findAllOrdersBySplitPage(Integer page, Integer limit, String keyword) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Order> list = new ArrayList<Order>();\n\t\tif(keyword != null && !keyword.trim().equals(\"\")) {\n\t\t\tlist = this.orderMapper.findOrdersByUserName(keyword);\n\t\t}else {\n\t\t\tlist = this.orderMapper.findAllOrders();\n\t\t}\n\t\tfor(Order order : list) {\n\t\t\torder.setOrder_user(this.userMapper.findUserById(order.getUser_id()));\n\t\t\tSchedule schedule = this.scheduleMapper.findScheduleById(order.getSchedule_id());\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\torder.setOrder_schedule(schedule);\n\t\t}\n\t\tPageInfo<Order> info = new PageInfo<Order>(list);\n\t\treturn info;\n\t}\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/ScheduleServiceImp.java",
    "content": "package com.service.imp;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.Hall;\nimport com.entity.Order;\nimport com.entity.Schedule;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.mapper.CinemaMapper;\nimport com.mapper.HallMapper;\nimport com.mapper.MovieMapper;\nimport com.mapper.OrderMapper;\nimport com.mapper.ScheduleMapper;\nimport com.service.IScheduleService;\n\n@Service\npublic class ScheduleServiceImp implements IScheduleService{\n\t@Autowired\n\tprivate ScheduleMapper scheduleMapper;\n\t@Autowired\n\tprivate HallMapper hallMapper;\n\t@Autowired\n\tprivate MovieMapper movieMapper;\n\t@Autowired\n\tprivate OrderMapper orderMapper;\n\t@Autowired\n\tprivate CinemaMapper cinemaMapper;\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic Schedule findScheduleById(long schedule_id) {\n\t\tSchedule schedule = this.scheduleMapper.findScheduleById(schedule_id);\n\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\tschedule.setSchedule_hall(hall);\n\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\tList<Order> list = this.orderMapper.findOrdersByScheduleId(schedule_id);\n\t\tschedule.setOrderList(list);\n\t\treturn schedule;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addSchedule(Schedule schedule) {\n\t\treturn this.scheduleMapper.addSchedule(schedule);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateSchedule(Schedule schedule) {\n\t\treturn this.scheduleMapper.updateSchedule(schedule);\n\t}\n\n\t/**\n\t * 场次下架功能 而非删除\n\t */\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer deleteSchedule(long schedule_id) {\n\t\treturn this.scheduleMapper.deleteSchedule(schedule_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addScheduleRemain(long schedule_id) {\n\t\treturn this.scheduleMapper.addScheduleRemain(schedule_id);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer delScheduleRemain(long schedule_id) {\n\t\treturn this.scheduleMapper.delScheduleRemain(schedule_id);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Schedule> findScheduleByMovieName(Integer page,Integer limit,String movie_name) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Schedule> schedules = this.scheduleMapper.findScheduleByMovieName(movie_name);\n\t\tfor(Schedule schedule: schedules) {\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\tList<Order> list = this.orderMapper.findOrdersByScheduleId(schedule.getSchedule_id());\n\t\t\tschedule.setOrderList(list);\n\t\t}\n\t\tPageInfo<Schedule> info = new PageInfo<Schedule>(schedules);\n\t\treturn info;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Schedule> findOffScheduleByMovieName(Integer page, Integer limit, String movie_name) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Schedule> schedules = this.scheduleMapper.findOffScheduleByMovieName(movie_name);\n\t\tfor(Schedule schedule: schedules) {\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\tList<Order> list = this.orderMapper.findOrdersByScheduleId(schedule.getSchedule_id());\n\t\t\tschedule.setOrderList(list);\n\t\t}\n\t\tPageInfo<Schedule> info = new PageInfo<Schedule>(schedules);\n\t\treturn info;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Schedule> findAllScheduleByState(Integer page,Integer limit,int schedule_state) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Schedule> schedules = this.scheduleMapper.findScheduleByState(schedule_state);\n\t\tfor(Schedule schedule: schedules) {\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\tList<Order> list = this.orderMapper.findOrdersByScheduleId(schedule.getSchedule_id());\n\t\t\tschedule.setOrderList(list);\n\t\t}\n\t\tPageInfo<Schedule> info = new PageInfo<Schedule>(schedules);\n\t\treturn info;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<Schedule> findAllSchedule(Integer page,Integer limit) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<Schedule> schedules = this.scheduleMapper.findAllSchedule();\n\t\tfor(Schedule schedule: schedules) {\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t\tList<Order> list = this.orderMapper.findOrdersByScheduleId(schedule.getSchedule_id());\n\t\t\tschedule.setOrderList(list);\n\t\t}\n\t\tPageInfo<Schedule> info = new PageInfo<Schedule>(schedules);\n\t\treturn info;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Schedule> findScheduleByCinemaAndMovie(long cinema_id, long movie_id) {\n\t\treturn this.scheduleMapper.findScheduleByCinemaAndMovie(cinema_id, movie_id);\n\t}\n\t\n\t/**\n\t * selectSeat页面提供接口\n\t */\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<Schedule> findScheduleByCineamIdAndMovieId(long cinema_id, long movie_id) {\n\t\tList<Schedule> list = this.scheduleMapper.findScheduleByCinemaAndMovie(cinema_id, movie_id);\n\t\tfor(Schedule schedule: list) {\n\t\t\tHall hall = this.hallMapper.findHallById(schedule.getHall_id());\n\t\t\thall.setHall_cinema(this.cinemaMapper.findCinemaById(hall.getCinema_id()));\n\t\t\tschedule.setSchedule_hall(hall);\n\t\t\tschedule.setSchedule_movie(this.movieMapper.findMovieById(schedule.getMovie_id()));\n\t\t}\n\t\treturn list;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/service/imp/UserServiceImp.java",
    "content": "package com.service.imp;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.entity.User;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.mapper.UserMapper;\nimport com.service.IUserService;\n\n@Service\npublic class UserServiceImp implements IUserService{\n\n\t@Autowired\n\tprivate UserMapper usermapper;\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic User login(String user_name, String user_pwd) {\n\t\tList<User> userList = usermapper.findUserByName(user_name);\n\t\tfor(User user : userList) {\n\t\t\tif(user.getUser_pwd().equals(user_pwd)) {\n\t\t\t\treturn user;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer updateUserInfo(User user) {\n\t\treturn this.usermapper.updateUser(user);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic User findUserById(long user_id) {\n\t\treturn this.usermapper.findUserById(user_id);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<User> findUserByName(String name) {\t\n\t\treturn this.usermapper.findUserByName(name);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer addUser(User user) {\n\t\treturn this.usermapper.addUser(user);\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class)\n\t@Override\n\tpublic Integer deleteUser(long user_id) {\n\t\treturn this.usermapper.deleteUser(user_id);\n\t}\n\t\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic PageInfo<User> findAllUserBySplitPage(Integer page, Integer limit, String keyword) {\n\t\tPageHelper.startPage(page, limit);\n\t\tList<User> list = new ArrayList<User>();\n\t\tif(keyword != null && !keyword.trim().equals(\"\")) {\n\t\t\tlist = this.usermapper.findUserLikeName(keyword);\n\t\t}else {\n\t\t\tlist = this.usermapper.findAllUser();\n\t\t}\n\t\tPageInfo<User> info = new PageInfo<User>(list);\n\t\treturn info;\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<User> findAllUserInfos() {\n\t\treturn this.usermapper.findAllUser();\n\t}\n\n\t@Transactional(propagation=Propagation.REQUIRED,readOnly=true)\n\t@Override\n\tpublic List<User> findUserLikeName(String name) {\n\t\treturn this.usermapper.findUserLikeName(name);\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/util/ResponseModel.java",
    "content": "package com.util;\n/**\n * 返回给浏览器的数据\n * @param success 状态 true:成功 false:失败\n * @param msg 提示信息\n * @author Wxj\n */\npublic class ResponseModel {\n\tprivate boolean success;\n\tprivate String msg;\n\t\n\tpublic boolean isSuccess() {\n\t\treturn success;\n\t}\n\tpublic void setSuccess(boolean success) {\n\t\tthis.success = success;\n\t}\n\tpublic String getMsg() {\n\t\treturn msg;\n\t}\n\tpublic void setMsg(String msg) {\n\t\tthis.msg = msg;\n\t}\n\t/**\n\t * 默认成功\n\t * @param msg\n\t */\n\tpublic ResponseModel(String msg) {\n\t\tthis.setSuccess(true);\n\t\tthis.setMsg(msg);\n\t}\n\tpublic ResponseModel(boolean success,String msg) {\n\t\tthis.setSuccess(success);\n\t\tthis.setMsg(msg);\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/util/UUIDUtil.java",
    "content": "package com.util;\n\nimport java.util.UUID;\n/**\n * 生产唯一标识符\n * @author Wxj\n */\npublic class UUIDUtil {\n\n\tpublic static String getUUID() {\n\t\tString str = UUID.randomUUID().toString();\n\t\tstr = str.replace(\"-\", \"\");\n\t\treturn str;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/util/test.java",
    "content": "package com.util;\n\nimport java.io.Console;\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.Random;\n\nimport com.alibaba.fastjson.JSONObject;\n\n\npublic class test {\n\n\tpublic static void main(String[] args) {\n//\t\tDate date = new Date();\n//\t\tjava.sql.Date zdate = new java.sql.Date(date.getYear(), date.getMonth(), date.getDay());\n//\t\tSystem.out.println(date);\n//\t\tSystem.out.println(zdate);\n//\t\tfor(int i = 0;i<20;i++) {\n//\t\tfloat random = 5 + (new Random().nextFloat() * 4);\n//\t\tDecimalFormat fnum = new DecimalFormat(\"##0.0\");  \n//\t\tString score = fnum.format(random);\n//\t\t//String rs = String.valueOf(random);\n//\t\tSystem.out.println(\"score:\" + score);\n//\t\t}\n\t\t\n\t\t\n//\t\tJSONObject obj = new JSONObject();\n//\t\tJSONObject hallobj = new JSONObject();\n//\t\t//ArrayList<String> cinemalist= new ArrayList<String>();\n//\t\tfor(int i = 0; i < 2;i++) {\n//\t\t\tArrayList<String> cinemalist= new ArrayList<String>();\n//\t\t\tfor(int j=0;j<2;j++) {\n//\t\t\t\tcinemalist.add(String.valueOf(j+1)+\"号厅\");\n//\t\t\t}\n//\t\t\thallobj.put(\"影院\"+String.valueOf(i),cinemalist);\n//\t\t}\n//\t\tobj.put(\"cinema\", hallobj);\n//\t\tSystem.out.println(obj);\n//\t\tJSONObject obj2 = obj.getJSONObject(\"cinema\");\n//\t\t//解析 1级\n//\t\tSystem.out.println(obj2);\n//\t\t//解析 2级\n//\t\tArrayList<String> halllist= new ArrayList<String>();\n//\t\thalllist = (ArrayList<String>)obj2.get(\"影院0\");\n//\t\tSystem.out.println(halllist.get(0));\n\t\t\n//\t\tArrayList<Integer> arr = new ArrayList<Integer>();\n//\t\tfor(int i = 0;i < 5;i++) {\n//\t\t\tarr.add(i);\n//\t\t}\n//\t\tSystem.out.println(arr.get(4));\n\t\t\n\t\t\n//\t\tDate date = new Date();\n//\t\tSimpleDateFormat dateFormat = new SimpleDateFormat(\"YYYYMMdd\");\n//\t\tString str = \"\";\n//\t\tstr += dateFormat.format(date);\n//\t\tSystem.out.println(str);\n//\t\tString [] str = {\"3排4座\",\"10排1座\",\"5排12座\",\"11排12座\"};\n//\t\tArrayList<String> arr = new ArrayList<String>();\n//\t\tfor(int i = 0;i < str.length;i++) {\n//\t\t\t//System.out.println(str[i].length());\n//\t\t\tString index = \"\";\n//\t\t\tswitch(str[i].length()) {\n//\t\t\t\tcase 4: \n//\t\t\t\t\tindex = \"0\" + str[i].replaceAll(\"排\", \"0\");\n//\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n//\t\t\t\t\tbreak;\n//\t\t\t\tcase 5:\n//\t\t\t\t\tif(str[i].charAt(2) >= 48 && str[i].charAt(2) <= 57) {\n//\t\t\t\t\t\tindex = \"0\" + str[i].replaceAll(\"排\", \"\");\n//\t\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n//\t\t\t\t\t}else {\n//\t\t\t\t\t\tindex = str[i].replaceAll(\"排\", \"0\");\n//\t\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n//\t\t\t\t\t}\n//\t\t\t\t\tbreak;\n//\t\t\t\tcase 6:\n//\t\t\t\t\tindex = str[i].replaceAll(\"排\", \"\"); \n//\t\t\t\t\tindex = index.replaceAll(\"座\", \"\");\n//\t\t\t\t\tbreak;\n//\t\t\t}\n//\t\t\tarr.add(index);\n//\t\t}\n//\t\tSystem.out.println(arr);\n\t\t\n\t\t//int price = 29;\n\t\t//float box = (float)price /10000;\n\t\t//System.out.println((float)price /10000);;\n//\t\tDecimalFormat fnum = new DecimalFormat(\"##0.0000\");  \n//\t\tString score = fnum.format(random);\n\t\t\n\t\tArrayList<Integer> arr = new ArrayList<>();\n\t\tArrayList<Integer> indexz = new ArrayList<>();\n\t\tint num[] = {1,2,3,0,5,0,6};\n\t\tfor(int i = 0;i<num.length;i++) {\n\t\t\tarr.add(num[i]);\n\t\t}\n\t\tfor(int z = 0;z<arr.size();z++) {\n\t\t\tif(arr.get(z) == 0) {\n\t\t\t\tindexz.add(z);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(arr);\n\t\tSystem.out.println(indexz);\n//\t\tarr.remove(3);\n\t\tfor(int y =0;y<indexz.size();y++) {\n\t\t\tint test = 0;\n\t\t\tint index = (indexz.get(y))-test;\n\t\t\tSystem.out.println(index);\n\t\t\tarr.remove(index);\n\t\t\ttest = test + 2;\n\t\t}\n\t\tSystem.out.println(arr);\n\t}\n}\n"
  },
  {
    "path": "src/main/resources/movie.sql",
    "content": "/*\r\n Navicat Premium Data Transfer\r\n\r\n Source Server         : localhost_3306\r\n Source Server Type    : MySQL\r\n Source Server Version : 50725\r\n Source Host           : localhost:3306\r\n Source Schema         : movie\r\n\r\n Target Server Type    : MySQL\r\n Target Server Version : 50725\r\n File Encoding         : 65001\r\n\r\n Date: 07/02/2020 15:24:12\r\n*/\r\n\r\nSET NAMES utf8mb4;\r\nSET FOREIGN_KEY_CHECKS = 0;\r\n\r\n-- ----------------------------\r\n-- Table structure for cinema\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `cinema`;\r\nCREATE TABLE `cinema`  (\r\n  `cinema_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '影院编号',\r\n  `cinema_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '影院名称',\r\n  `cinema_address` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '影院地址',\r\n  PRIMARY KEY (`cinema_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of cinema\r\n-- ----------------------------\r\nINSERT INTO `cinema` VALUES (1, '中山奇幻电影院', '石岐区岐头新村龙凤街4号大信溢彩荟二期8楼');\r\nINSERT INTO `cinema` VALUES (2, '金逸影城中山石歧店', '石岐区大信南路2路大信新都汇5楼');\r\nINSERT INTO `cinema` VALUES (3, '博纳国际影城（中山IMAX店）', '古镇区同兴路98号利和广场购物中心四楼4009号');\r\nINSERT INTO `cinema` VALUES (4, 'UME影城（中山古镇店）', '古镇区中兴大道南一号花艺广场11层A区');\r\nINSERT INTO `cinema` VALUES (5, '中影100影城石歧店', '石岐区康华路15号恒基大厦3楼');\r\nINSERT INTO `cinema` VALUES (6, '橙天嘉禾影城（利和店）', '石岐区中山三路16号利和广场五层');\r\nINSERT INTO `cinema` VALUES (7, '珠影GCC影城（中山杜比全景声店）', '火炬高技术产业开发区火炬开发区港城路7号明珠广场二期');\r\nINSERT INTO `cinema` VALUES (8, '期遇·翼影城（东凤店）', '东凤镇东富路81号大顺时尚荟广场B座四楼（原君信大厦）');\r\nINSERT INTO `cinema` VALUES (9, '中山IM电影城（南朗壹加壹店）', '南朗镇岭南路62号新壹加壹4楼');\r\nINSERT INTO `cinema` VALUES (10, '艺达国际影城（小榄杜比全景声店）', '小榄镇新华中路118号大信新都汇118广场4楼');\r\nINSERT INTO `cinema` VALUES (11, '中影天乐电影城（海州汇海城店）', '古镇镇古镇海州市场汇海城北门电梯5楼（星海湾对面）');\r\nINSERT INTO `cinema` VALUES (12, '比高电影城（中山店）', '坦洲镇坦神北路118号皇爵假日广场4楼');\r\nINSERT INTO `cinema` VALUES (13, '大地影院（星宝时代店）', '沙溪镇乐群坎溪村（星宝路6号星宝时代广场）');\r\nINSERT INTO `cinema` VALUES (14, '中影星艺影城（南朗车站店）', '南朗镇南朗车站2楼');\r\nINSERT INTO `cinema` VALUES (15, '中影太阳城影院（张家边店）', '火炬高技术产业开发区东镇东一路23号太阳城购物中心4楼（近群英华庭）');\r\nINSERT INTO `cinema` VALUES (16, '五月花电影城（棕榈彩虹商业中心店）', '西区街道棕榈彩虹商业中心1座三楼（近新中医院）');\r\nINSERT INTO `cinema` VALUES (17, '高菲影城（中山万益广场店）', '板芙镇迎宾大道8号（万益广场店）');\r\nINSERT INTO `cinema` VALUES (18, '金逸影城（中山远洋城IMAX店）', '东区街道博爱六路28号远洋广场3幢大信新都汇4楼');\r\n\r\n-- ----------------------------\r\n-- Table structure for comment\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `comment`;\r\nCREATE TABLE `comment`  (\r\n  `comment_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '评论编号',\r\n  `user_id` bigint(10) NOT NULL COMMENT '所属用户编号',\r\n  `comment_content` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '评论内容',\r\n  `movie_id` bigint(10) NOT NULL COMMENT '所属电影编号',\r\n  `comment_time` datetime(0) NOT NULL COMMENT '评论时间',\r\n  PRIMARY KEY (`comment_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 57 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of comment\r\n-- ----------------------------\r\nINSERT INTO `comment` VALUES (3, 1, '不容错过1', 3, '2020-02-06 16:10:38');\r\nINSERT INTO `comment` VALUES (4, 1, '车开电车侧壁如履平地，足踢卫星返回舱一脚拯救东京，我看柯南跟吴京此生必有一战吧', 4, '2019-07-13 11:15:01');\r\nINSERT INTO `comment` VALUES (5, 1, '看到最后一直在想真正的主角【皮球】怎么还不登场，结果果然没有让我失望。哦对，主役是皮球的话，二番就是安室的车了吧。', 5, '2019-07-13 11:15:14');\r\nINSERT INTO `comment` VALUES (7, 1, '东南亚电影院的观众们同时发出了杠铃般的笑声', 7, '2019-07-13 04:31:17');\r\nINSERT INTO `comment` VALUES (8, 1, '谁要看你们检察院公安撕逼 我操 还我黑衣人组织', 8, '2019-07-13 11:15:51');\r\nINSERT INTO `comment` VALUES (9, 1, '咸水族的那个帝王蟹，好像很好吃的样子！', 9, '2019-07-13 11:16:17');\r\nINSERT INTO `comment` VALUES (10, 1, '还行，没吹得那么好，有点像强化娱乐性的海底版《黑豹》...故事线极其简单，打戏遍布扩成了143分钟的篇幅，对路人非常友好，不过这类过度炫目眼花缭乱的特效已经越看越麻木，什么海底《阿凡达》吹太过了，坐等《阿凡达2》的潘多拉海底世界吊打吧', 10, '2019-07-13 11:16:34');\r\nINSERT INTO `comment` VALUES (12, 2, '女王：维科，这是我大儿子，剩下的话不用我多说了吧，以后该怎么办，你自己招子放亮一点，好处不会少了你的。维科：晓得了。zz', 2, '2019-07-20 02:21:17');\r\nINSERT INTO `comment` VALUES (13, 2, '东有沉香劈山救母，西有海娃寻叉救母。绿色秋裤哲学变身，刺身放题海底大战。同母异父兄弟相残，弟妹大伯不伦之恋。温子仁携手徐锦江，亚裔之光拯救好莱坞！', 3, '2019-07-13 11:28:40');\r\nINSERT INTO `comment` VALUES (14, 2, '2.5 “我的恋人，就是这个国家啊！”———————好久没有听到这么烂的话了', 4, '2019-07-13 11:33:21');\r\nINSERT INTO `comment` VALUES (15, 2, '今年的柯南剧场版好无聊啊。。后面那段飙车简直夸张到无法理解，故事最后的反转也很让人无语，完全是多此一举，没有好的剧本就别拍了好吗，估计上映了也捞不到太多票房。ps:韩语版的柯南真的让人看得别扭不舒服..', 5, '2019-07-13 11:35:46');\r\nINSERT INTO `comment` VALUES (16, 2, '渔夫和灯塔守护多数是鳏夫，私下里经常养一些人鱼交欢。海洋远比陆地深远得多，人们赞美阳光下的海洋，却不知深夜降临海面上会冒出可怕的妖怪，海底也会藏着嘲笑人类的高级文明。所以！温子仁同样是一个借大热系列ip来讲自己故事的导演！', 6, '2019-07-13 11:36:08');\r\nINSERT INTO `comment` VALUES (17, 2, '海王可能要被微博营销号给奶死了。。。', 7, '2019-07-13 11:36:14');\r\nINSERT INTO `comment` VALUES (18, 2, '当陆地人为自己的文明沾沾自喜时，亚特兰蒂斯的服装设计已经领先我们几百年。', 8, '2019-07-13 11:36:41');\r\nINSERT INTO `comment` VALUES (19, 2, '温子仁就像一个从没拍过特效大片的暴发户。两星半，降降火。', 9, '2019-07-13 11:36:50');\r\nINSERT INTO `comment` VALUES (20, 2, '剧本，导演都有问题，很多片段都似曾相识，硬是凑了两个半小时真是辛苦了我的膀胱。然而剧情不够美工来凑，海底阿凡达，温子仁难担大任，DC要超越漫威还有很长的路要走。', 10, '2019-07-13 11:36:58');\r\nINSERT INTO `comment` VALUES (21, 3, '故事果然还是DC常规水准，营销能力那真是突飞猛进了，有点好奇温子仁拍西游记定海神针篇会是什么效果。本马王粉反而觉得本片最帅的是前面拉了皮的威廉达福……', 2, '2019-07-13 11:37:32');\r\nINSERT INTO `comment` VALUES (22, 3, '前面的小男孩突然问起诉是什么意思，我就在想这个故事小孩看得懂吗？动作场景依然需要帮忙按住牛顿的棺材板。', 4, '2019-07-13 11:37:43');\r\nINSERT INTO `comment` VALUES (23, 3, '7分。温子仁确实很厉害，原以为这该是系列中最无趣的一部，尤其各种水下戏份。结果，却难得拍的很好看。影片节奏感和大场面掌控上，确实很见功力。以及，温子仁还融入了很多他自己的趣味，也算很有趣的细节了。整体可看性还不错，就是略长了，海底的光怪陆离，看久了也会有些视觉疲劳。', 5, '2019-07-13 11:38:06');\r\nINSERT INTO `comment` VALUES (24, 3, '渔夫和灯塔守护多数是鳏夫，私下里经常养一些人鱼交欢。海洋远比陆地深远得多，人们赞美阳光下的海洋，却不知深夜降临海面上会冒出可怕的妖怪，海底也会藏着嘲笑人类的高级文明。所以！温子仁同样是一个借大热系列ip来讲自己故事的导演！', 3, '2019-07-13 11:38:35');\r\nINSERT INTO `comment` VALUES (25, 3, '故事老套了一点 但是昨晚我的主要任务是努力让自己不要在影院里发大水…Jason太尼玛适合这个角色了，就算他能轻而易举的把我操坏我也心甘情愿地承受这份痛苦', 9, '2019-07-13 11:39:10');\r\nINSERT INTO `comment` VALUES (26, 4, '飞机里的那一段是纪念，也是传承。钢铁侠说过，我们做的一切其实并不重要，重要的是我们选择给后代留下什么。而蜘蛛侠是托尼留给我们最好的遗产。', 10, '2019-07-13 11:39:30');\r\nINSERT INTO `comment` VALUES (27, 4, '多年以后，面对敌人，蜘蛛侠彼得·帕克将会回想起，托尼·斯塔克带他见识超级英雄们的那个遥远的下午。 两个彩蛋比正片有意思', 7, '2019-07-13 11:39:41');\r\nINSERT INTO `comment` VALUES (28, 4, '轻轻松松、啪啪砰砰，这样的超级英雄电影不挺好？温子仁真DC良心大管家——从头到尾堆特效，经费才烧1.6亿！欣赏不来海王徐锦江，51岁的妮可真的美炸了~~~~~', 6, '2019-07-13 11:39:57');\r\nINSERT INTO `comment` VALUES (29, 4, '天空属于卢卡斯 陆地属于杰克逊 海洋属于温子仁！！！', 2, '2019-07-13 11:40:13');\r\nINSERT INTO `comment` VALUES (30, 4, '特效和场景都非常不错，但是剧情和主角都非常不真实，唯一的真实人类就是那个收到新衣服以后改颜色镶铆钉的生命力很旺盛的青蛙反派。', 8, '2019-07-13 11:40:20');\r\nINSERT INTO `comment` VALUES (32, 5, '3.5；失落的亚特兰蒂斯之国，古远传说提供与一般超英片迥异的丰富背景，DC另辟蹊径，开启美妙神秘的水下世界，星站兵密集，温子仁不负众望且适时塞私货，海沟一战jump scare其乐无穷。视效惊人，音效震人，抛却鸡汤亲情，大场面调度甚是过瘾。妮可基德曼真·女神，形象太契合。', 2, '2019-07-13 11:41:14');\r\nINSERT INTO `comment` VALUES (33, 5, '我宣布！2018就是骨科文艺复兴之年！！！', 9, '2019-07-13 11:41:29');\r\nINSERT INTO `comment` VALUES (38, 2, '毒液好丑啊', 1, '2019-07-21 06:40:43');\r\nINSERT INTO `comment` VALUES (39, 4, '哇，这个毒液真的丑，但是女主真的好看！', 1, '2019-07-21 08:59:44');\r\nINSERT INTO `comment` VALUES (40, 6, '以为是R级片，结果是儿童片。汤老湿毫无邪气只有痞气，把一个反派英雄演得正气凛然到闷，而且毒液跟《寄生兽》一样竟然养着养着就变宠物了77', 1, '2019-07-21 09:04:27');\r\nINSERT INTO `comment` VALUES (41, 5, '无名之辈@@', 3, '2019-07-21 09:05:03');\r\nINSERT INTO `comment` VALUES (42, 5, '你好之华', 5, '2019-07-21 09:05:46');\r\nINSERT INTO `comment` VALUES (43, 6, '你的眼睛像火蜥蜴是我笨拙的情话，疯子离开懦夫是她最凶的咒骂，交换亲人让我的愧疚在博格特前显形，歃血为盟使我的爱在厄里斯镜里再现。点金石可以长生，纳吉尼终会成兽，爱心咒语不能保证天长地久，万咒皆终无法阻止核爆之灾。听说魔法世界也有很多爱恨与无奈，麻瓜世界里今年我的入学信还是被寄丢。', 2, '2019-07-21 09:06:34');\r\nINSERT INTO `comment` VALUES (44, 6, '活人办了葬礼，死人偏剩一口气。手机那头她是暗夜里绽放的花，天台边缘她是绝路尽头的桥。两个抢手机模型的憨皮，却无比清醒地看到对方的痴，何惧陷阱，哪管嫌疑。有的人是还没剥开的蛋壳，有的人是胸口夹带的铁板，有的人是虚张声势的水枪，有的人是无法愈合的伤口。几分痴憨皆是勇，几句咒骂都是爱。', 3, '2019-07-21 09:07:47');\r\nINSERT INTO `comment` VALUES (45, 3, '毒液好恶心，快看吐了。', 1, '2019-07-21 09:08:33');\r\nINSERT INTO `comment` VALUES (46, 6, '在岩井俊二的作品里算不上好，但也不差。里面的“时空信息传递”、“替身与错位”，看似是《情书》的反面，实则挖掘的是家庭代际的空间，引出稍显过满的群戏——每个角色都有互文关系。演员方面重点夸下金马提名的张子枫，没想到她竟是戏眼，两次落泪都是因为她。', 5, '2019-07-21 09:08:54');\r\nINSERT INTO `comment` VALUES (47, 3, '允儿来了zz', 1, '2019-07-21 09:09:21');\r\nINSERT INTO `comment` VALUES (48, 6, '顶顶顶', 4, '2019-07-21 09:09:23');\r\nINSERT INTO `comment` VALUES (49, 6, '别想着拍给年轻人看，拍给人看行不行。', 15, '2019-07-21 09:10:12');\r\nINSERT INTO `comment` VALUES (50, 6, '古天乐又缺钱建学校了', 16, '2019-07-21 09:10:38');\r\nINSERT INTO `comment` VALUES (51, 6, '以为玩三就完结甚至不敢期待怕失望，然而完全是惊喜。新元素加入很出彩，Woody找到归属，我的玩具系列完美结局。', 17, '2019-07-21 09:11:04');\r\nINSERT INTO `comment` VALUES (52, 6, '有点泰国惊悚片的味道了，说实话我好几次被吓的冷汗都出来了；虽然有一些场景还是感觉逻辑不通，但至少画面和节奏不渣。本来我都不知道这部电影，但是我对象说要看，那就看了这部，现在的问题是，他不在家的时候我怎么办？', 18, '2019-07-21 09:11:39');\r\nINSERT INTO `comment` VALUES (53, 6, '一个悲伤的故事：太阳都要毁灭，地球都要流浪了，我国的校服还是这么丑......', 20, '2019-07-21 09:12:06');\r\nINSERT INTO `comment` VALUES (54, 6, '不拍妓女三部曲的陈果就不是陈果了。电影拍得跟开玩笑一样。就像故事的走向，演员的演法，都带着些玩世不恭。而这不是诙谐是轻佻。观众并不想看你们在大银幕开玩笑。', 21, '2019-07-21 09:12:31');\r\nINSERT INTO `comment` VALUES (55, 3, '我的青春也全都是你呀', 26, '2019-07-21 09:19:26');\r\nINSERT INTO `comment` VALUES (56, 3, '我是superAdmin，欢迎大家评论', 1, '2020-02-06 15:00:54');\r\n\r\n-- ----------------------------\r\n-- Table structure for hall\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `hall`;\r\nCREATE TABLE `hall`  (\r\n  `hall_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '放映厅编号',\r\n  `hall_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '放映厅名称',\r\n  `hall_capacity` int(10) NOT NULL DEFAULT 144 COMMENT '放映厅容量 默认为144  12 x 12 ',\r\n  `cinema_id` bigint(10) NOT NULL COMMENT '所属影院编号',\r\n  PRIMARY KEY (`hall_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 52 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of hall\r\n-- ----------------------------\r\nINSERT INTO `hall` VALUES (1, '1号厅', 144, 1);\r\nINSERT INTO `hall` VALUES (2, '1号厅', 144, 2);\r\nINSERT INTO `hall` VALUES (3, '1号厅', 144, 3);\r\nINSERT INTO `hall` VALUES (4, '1号厅', 144, 4);\r\nINSERT INTO `hall` VALUES (5, '1号厅', 144, 5);\r\nINSERT INTO `hall` VALUES (6, '1号厅', 144, 6);\r\nINSERT INTO `hall` VALUES (7, '2号厅', 144, 1);\r\nINSERT INTO `hall` VALUES (8, '2号厅', 144, 2);\r\nINSERT INTO `hall` VALUES (9, '2号厅', 144, 3);\r\nINSERT INTO `hall` VALUES (10, '2号厅', 144, 4);\r\nINSERT INTO `hall` VALUES (11, '2号厅', 144, 5);\r\nINSERT INTO `hall` VALUES (12, '2号厅', 144, 6);\r\nINSERT INTO `hall` VALUES (13, '3号厅', 144, 1);\r\nINSERT INTO `hall` VALUES (14, '1号厅', 144, 7);\r\nINSERT INTO `hall` VALUES (15, '1号厅', 144, 8);\r\nINSERT INTO `hall` VALUES (16, '1号厅', 144, 9);\r\nINSERT INTO `hall` VALUES (17, '1号厅', 144, 10);\r\nINSERT INTO `hall` VALUES (18, '1号厅', 144, 11);\r\nINSERT INTO `hall` VALUES (19, '1号厅', 144, 12);\r\nINSERT INTO `hall` VALUES (20, '1号厅', 144, 13);\r\nINSERT INTO `hall` VALUES (21, '1号厅', 144, 14);\r\nINSERT INTO `hall` VALUES (22, '1号厅', 144, 15);\r\nINSERT INTO `hall` VALUES (23, '1号厅', 144, 16);\r\nINSERT INTO `hall` VALUES (24, '1号厅', 144, 17);\r\nINSERT INTO `hall` VALUES (25, '1号厅', 144, 18);\r\nINSERT INTO `hall` VALUES (26, '2号厅', 144, 7);\r\nINSERT INTO `hall` VALUES (27, '2号厅', 144, 8);\r\nINSERT INTO `hall` VALUES (28, '2号厅', 144, 9);\r\nINSERT INTO `hall` VALUES (29, '2号厅', 144, 10);\r\nINSERT INTO `hall` VALUES (30, '2号厅', 144, 11);\r\nINSERT INTO `hall` VALUES (31, '2号厅', 144, 12);\r\nINSERT INTO `hall` VALUES (32, '2号厅', 144, 13);\r\nINSERT INTO `hall` VALUES (33, '2号厅', 144, 14);\r\nINSERT INTO `hall` VALUES (34, '2号厅', 144, 15);\r\nINSERT INTO `hall` VALUES (35, '2号厅', 144, 16);\r\nINSERT INTO `hall` VALUES (36, '2号厅', 144, 17);\r\nINSERT INTO `hall` VALUES (37, '2号厅', 144, 18);\r\nINSERT INTO `hall` VALUES (38, '3号厅', 144, 3);\r\nINSERT INTO `hall` VALUES (39, '3号厅', 144, 5);\r\nINSERT INTO `hall` VALUES (40, '3号厅', 144, 7);\r\nINSERT INTO `hall` VALUES (41, '3号厅', 144, 10);\r\nINSERT INTO `hall` VALUES (42, '3号厅', 144, 11);\r\nINSERT INTO `hall` VALUES (43, '3号厅', 144, 15);\r\nINSERT INTO `hall` VALUES (44, '3号厅', 144, 18);\r\nINSERT INTO `hall` VALUES (45, 'IMAX厅', 144, 1);\r\nINSERT INTO `hall` VALUES (46, 'IMAX厅', 144, 3);\r\nINSERT INTO `hall` VALUES (47, 'IMAX厅', 144, 8);\r\nINSERT INTO `hall` VALUES (48, 'IMAX厅', 144, 12);\r\nINSERT INTO `hall` VALUES (49, 'IMAX厅', 144, 14);\r\nINSERT INTO `hall` VALUES (50, 'IMAX厅', 144, 16);\r\nINSERT INTO `hall` VALUES (51, 'IMAX厅', 144, 17);\r\n\r\n-- ----------------------------\r\n-- Table structure for movie\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `movie`;\r\nCREATE TABLE `movie`  (\r\n  `movie_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '电影编号',\r\n  `movie_cn_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '电影名称（中文）',\r\n  `movie_fg_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '电影名称（外语）',\r\n  `movie_actor` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影演职人员',\r\n  `movie_director` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影导演',\r\n  `movie_detail` varchar(350) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影详情',\r\n  `movie_duration` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影时长',\r\n  `movie_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影类型',\r\n  `movie_score` float(10, 1) NULL DEFAULT 0.0 COMMENT '电影评分 默认为0',\r\n  `movie_boxOffice` float(10, 4) NULL DEFAULT 0.0000 COMMENT '电影票房 默认为0',\r\n  `movie_commentCount` bigint(10) NULL DEFAULT 0 COMMENT '电影参评人数 默认为0',\r\n  `movie_releaseDate` date NOT NULL COMMENT '电影上映时间',\r\n  `movie_country` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影制片地区',\r\n  `movie_picture` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影海报',\r\n  `movie_state` int(3) NOT NULL DEFAULT 1 COMMENT '电影状态 默认为1  1：在线 0：下架',\r\n  PRIMARY KEY (`movie_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of movie\r\n-- ----------------------------\r\nINSERT INTO `movie` VALUES (1, '毒液：致命守护者', 'Venom', '汤姆·哈迪:埃迪·布洛克/毒液,米歇尔·威廉姆斯:安妮·韦英', '鲁本·弗雷斯彻', '身为记者的埃迪·布洛克（汤姆·哈迪饰）在调查生命基金会老板卡尔顿·德雷克（里兹·阿迈德饰）的过程中，事业遭受重创，与未婚妻安妮·韦英（米歇尔·威廉姆斯饰）的关系岌岌可危，并意外被外星共生体控制，他历经挣扎对抗，最终成为拥有强大超能力，无人可挡的“毒液“', '107分钟', '动作，科幻', 7.2, 1.0220, 6, '2019-06-24', '美国', '../upload/movies/Venom.jpg', 1);\r\nINSERT INTO `movie` VALUES (2, '神奇动物：格林德沃之罪', 'Fantastic Beasts: The Crimes of Grindelwald', '埃迪·雷德梅恩:纽特·斯卡曼德,凯瑟琳·沃特斯顿:蒂娜‧戈德斯坦,约翰尼·德普:盖勒·格林德沃', '大卫·叶茨', '在《神奇动物在那里》第一部的结尾，纽特·斯卡曼德（埃迪·雷德梅恩 饰）协助美国魔法国会，将强大的黑巫师盖勒特·格林德沃（约翰尼·德普 饰）抓捕归案。但格林德沃不久便兑现狂言成功越狱，并开始纠集信徒，着手实现他们的邪恶目的：让纯血统的巫师成为统治阶层，镇压一切非魔法生物。为挫败格林德沃的阴谋，阿不思·邓布利多（裘德·洛 饰）向昔日的学生纽特·斯卡曼德寻求帮助。纽特欣然允诺，却没有意识到，他将踏上的会是一段充满艰险的未来征途。此时的魔法世界面临空前的分裂乱局，阶层鸿沟日益加深，爱与忠诚备受考验，至亲好友也可能反目成仇……', '134分钟', '奇幻，冒险', 7.7, 1.0236, 5, '2019-06-25', '美国', '../upload/movies/Fantastic Beasts.jpg', 1);\r\nINSERT INTO `movie` VALUES (3, '无名之辈', 'A Cool Fish', '陈建斌:马先勇,任素汐:马嘉旗,潘斌龙:李海根', '饶晓志', '在一座山间小城中，一对低配劫匪、一个落魄的泼皮保安、一个身体残疾却性格彪悍的残毒舌女以及一系列生活在社会不同轨迹上的小人物，在一个貌似平常的日子里，因为一把丢失的老枪和一桩当天发生在城中的乌龙劫案，从而被阴差阳错地拧到一起，发生的一幕幕令人啼笑皆非的荒诞喜剧', '108分钟', '荒诞，喜剧', 9.2, 1.0315, 5, '2019-07-05', '中国大陆', '../upload/movies/A Cool Fish.jpg', 1);\r\nINSERT INTO `movie` VALUES (4, '名侦探柯南：零的执行人', '名探偵コナン ゼロの執行人', '高山南:江户川柯南,山崎和佳奈:毛利兰,林原惠美:灰原哀', '立川让', '5月1日，东京湾边的新建筑“海洋边缘”将举办首脑云集的东京峰会。然而，峰会开办前一周，会场发生超大规模的爆炸事件，并出现了安室透的身影。疑似恐怖袭击的事件引起了警察部门的严肃调查。在警察局大型搜查会议上，公安部门提交证物，却发现疑犯指纹与毛利小五郎（小山力也 配音）指纹吻合。作为律师的妃英理努力收集证据证明丈夫的无辜，却无力阻止毛利小五郎被收监。看到毛利兰（山崎和佳奈 配音）绝望哭泣的样子，柯南（高山南 配音）决定调查事件真相，还毛利小五郎清白。另一方面，少年侦探团的孩子们正紧密关注着无人探测器“天鹅”的回航任务。行踪诡异的安室透、惨遭陷害的毛利小五郎、错综复杂的警察部门、即将着陆的无人探测器；随着“机密任务”进入倒计时，关乎整个东京的可怕计划拉开帷幕…', '111分钟', '悬疑，冒险，动画', 8.5, 1.0064, 4, '2019-07-13', '日本', '../upload/movies/名探偵.jpg', 1);\r\nINSERT INTO `movie` VALUES (5, '你好，之华', 'Last Letter', '周迅:袁之华,秦昊:尹川,杜江:周文涛', '岩井俊二', '有人慌张得见面，有人简单地告别。姐姐袁之南离世的那个清晨，只匆匆留下一封信和一张同学会邀请函。妹妹之华(周迅 饰)代替姐姐参加，却意外遇见年少时的倾慕对象尹川（秦昊 饰）。往日的记忆在苏醒，但再次相见，已物是人非', '114分钟', '爱情', 7.9, 1.0000, 5, '2019-07-20', '中国大陆、日本', '../upload/movies/Last Letter.jpg', 1);\r\nINSERT INTO `movie` VALUES (6, '恐龙王', 'DINO KING', '吕佩玉:钢妈,王衡:斑大师,孙晔:八百度', '施雅雅', '陆地霸主特暴龙“斑大师”和自己的小儿子“小疙瘩”生活在一起。“小疙瘩”自幼失去了母亲，生性懦弱，严厉的“斑大师”虽然心底十分疼爱自己的孩子，但是急于让“小疙瘩”成长为新的陆地霸主，常常忍不住责骂“小疙瘩”，父子俩虽然相依为命，却始终有一些隔阂。 一天“小疙瘩”被几只邪恶的恐爪龙抓走，“斑大师”踏上漫漫的寻子之路，路途中他结识了有高度近视眼的美甲龙“八百度”，两人穿过“巨蝎峡”、走出“长颈龙绿洲”、踏上火山峡谷，经历了重重难关。而身处险境的“小疙瘩”也结识了一些新的朋友，并且开始和邪恶的恐爪龙斗智斗勇。最终父子两人终于相见，但是却不得不一起面对一个更加凶恶的史前怪物……', '95分钟', '喜剧，动画，冒险', 8.9, 1.0000, 2, '2018-12-10', '中国大陆', '../upload/movies/DINO KING.jpg', 0);\r\nINSERT INTO `movie` VALUES (7, '冰封侠：时空行者', 'Bing Feng Xia II', '甄子丹:贺英,黄圣依:小美,王宝强:萨獒', '叶伟民', '明朝大将军贺英（甄子丹 饰）利用时空金球终于重返明朝，与锦衣卫兄弟萨獒（王宝强 饰）获悉了倭寇和朝廷奸党之间足以倾覆皇权的密谋，绵延400年的惊天危机一触即发。贺英也在红颜知己小美（黄圣依 饰）的帮助下开始了抗倭锄奸和保护族人的战斗', '87分钟', '剧情，动作', 4.1, 1.0000, 3, '2018-09-02', '中国大陆', '../upload/movies/Bing Feng Xia II.jpg', 0);\r\nINSERT INTO `movie` VALUES (8, '梦境之源', 'Source of Dreams', '陈志朋:徐朗,颜丹晨:李雪,方中信:梁文道', '柳珂', '货车司机李昂由于童年时代内向懦弱，颓废度日，频频做噩梦，严重影响了正常的生活，并因此不得不接受心理医生曹井润的催眠治疗，却在梦境中意外卷入一场凶杀案。睿智破案的警探成为凶手，而真正的幕后黑手仍在逍遥法外……', '90分钟', '悬疑，推理', 5.9, 1.0000, 3, '2018-11-16', '中国大陆', '../upload/movies/Source of Dreams.jpg', 0);\r\nINSERT INTO `movie` VALUES (9, '摘金奇缘', 'Crazy Rich Asians', '吴恬敏:朱瑞秋,亨利·戈尔丁:杨尼克,杨紫琼:杨爱莉', '朱浩伟', '新加坡富二代王子杨尼克（亨利·戈尔丁饰）自豪地带着美丽大方、学识傲人的女友朱瑞秋（吴恬敏饰）回家见亲友。而这个巨富大家族对朱瑞秋的态度，与她的想像相差十万八千里远，朱瑞秋一开始以为只是跟深爱的男人轻松浪漫地度假，不料却面对排山倒海般的压力，她必须坚强应对一群有心机的情敌和反对者，但更难搞的竟然是她的准婆婆杨爱莉（杨紫琼饰），因为埃莉诺认为朱瑞秋这个现代美国女孩永远都高攀不上她们家', '120分钟', '喜剧，爱情', 6.1, 1.0000, 4, '2018-11-30', '美国', '../upload/movies/Crazy Rich Asians.jpg', 0);\r\nINSERT INTO `movie` VALUES (10, '海王', 'Aquaman', '杰森·莫玛:海王/亚瑟·库瑞,艾梅柏·希尔德:海后/湄拉,威廉·达福:努迪斯·维科', '温子仁', '在一场狂风暴雨的海边灯塔看守人汤姆·库瑞（特穆拉·莫里森饰）救了受伤的亚特兰蒂斯女王亚特兰娜（妮可·基德曼饰）之后，他们相爱了，生下了拥有半人类、半亚特兰蒂斯人的血统亚瑟·库瑞（杰森·莫玛饰）。为了救自己的爱人和儿子亚特兰娜选择了离开。\\r\\n几年之后，亚特兰娜被迫回到海底国家缔结政治婚姻，生下儿子奥姆（帕特里克·威尔森饰）。奥姆长大后当上国王对陆地人类充满憎恨，开始吞并海底中发展中的国家的兵力，一举消灭陆地人。奥姆的未婚妻海底王国泽贝尔公主湄拉（艾梅柏·希尔德饰）打算阻止这场战争，她到陆地找回亚瑟，让他以亚特兰娜女王长子身份回亚特兰蒂斯把王位争回来，而且湄拉要协助亚瑟找回能统治大海的失落的三叉戟', '143分钟', '动作，科幻', 7.6, 1.0000, 3, '2018-12-07', '美国、澳大利亚', '../upload/movies/Aquaman.jpg', 0);\r\nINSERT INTO `movie` VALUES (15, '素人特工', 'The Rookies', '王大陆:赵风,张榕容:淼淼', '袁锦麟', '极限运动达人赵风（王大陆 饰），误打误撞闯入了一场国际犯罪交易，不得不跟随国际特工（米拉·乔沃维奇 饰）一起前往布达佩斯。在这里他与废柴刑警淼淼（张榕容 饰）、民间科学家丁山（许魏洲 饰）与待业医生LV（刘美彤 饰）组成一支素人特工小队。这四个特工小白和高级国际特攻米拉一起，与恐怖分子开启了一场又惊又喜的斗争。', '113分钟', '喜剧,动作,冒险', 7.2, 1.0000, 1, '2019-07-12', '中国大陆', '../upload/movies/素人特工.jpg', 1);\r\nINSERT INTO `movie` VALUES (16, '追龙Ⅱ', 'Chasing the Dragon Ⅱ', '梁家辉:龙志强,古天乐:何天', '王晶', '悍匪龙志强（梁家辉 饰），在香港回归前，趁香港英政府不作为，而屡犯巨案，先后绑架富豪利家及雷家之长子，勒索超过二十亿元，事主怕被报复, 交赎款后都不敢报警。中国公安部极为关注，与香港警方合力，派香港警员何天（古天乐 饰）卧底潜入龙志强犯罪团伙，发现他正策划绑架澳门富豪贺不凡，最终陆港警察合力勇擒龙志强，救出贺不凡', '103分钟', '犯罪,剧情,动作', 7.9, 1.0000, 1, '2019-06-06', '中国大陆、中国香港', '../upload/movies/追龙Ⅱ.jpg', 1);\r\nINSERT INTO `movie` VALUES (17, '玩具总动员4', 'Toy Story 4', '汤姆·汉克斯:胡迪,蒂姆·艾伦:巴斯光年', '乔什·库雷', '当邦妮将所有玩具带上房车家庭旅行时，胡迪（汤姆·汉克斯 配音）与伙伴们将共同踏上全新的冒险之旅，领略房间外面的世界有多广阔，甚至偶遇老朋友牧羊女（安妮·波茨 配音）。在多年的独自闯荡中，牧羊女已经变得热爱冒险，不再只是一个精致的洋娃娃。正当胡迪和牧羊女发现彼此对玩具的使命的意义大相径庭时，他们很快意识到更大的威胁即将到来。', '100分钟', '喜剧,动画,奇幻', 9.1, 1.0000, 1, '2019-06-21', '美国', '../upload/movies/玩具总动员4.jpg', 1);\r\nINSERT INTO `movie` VALUES (18, '碟仙', 'Mortal Ouija', '黄奕:梦瑶,范逸臣:项天', '廉涛', '以网络直播为业的单亲妈妈梦瑶（黄奕 饰）带着上幼儿园的女儿雯雯住进了一栋便宜的学区房，然而，屋里的诡异氛围，与不时散发的奇怪恶臭，令梦瑶感到不安。某夜，雯雯竟然在梦游中，玩了前租客遗留的“碟仙”游戏。传说只要玩过的人，七日内必会被碟仙夺命！紧接着，屋内接连发生令人毛骨悚然的怪事。七日大限将至，眼看爱女危在旦夕，为了解开碟仙诅咒，夺回女儿，绝望的妈妈不惜做出了惊人的举动……', '83分钟', '恐怖,惊悚', 7.9, 1.0056, 1, '2019-06-21', '中国大陆', '../upload/movies/碟仙.jpg', 1);\r\nINSERT INTO `movie` VALUES (19, '扫毒', 'The White Storm', '古天乐:苏建秋,刘青云:马昊天', '陈木胜', '以马昊天（刘青云 饰）为首的毒品调查科，与手下张子伟（张家辉 饰）和卧底苏建秋（古天乐 饰）在执行一次跨国的大型扫毒行动中，被毒犯巨头八面佛（卢海鹏 饰）暗中揭发反埋伏，最终全军覆没。面对生死关头，三位主角为求活存，被迫命运扭转，展开一场残酷的人生战役。', '134分钟', '剧情,犯罪', 8.9, 1.0000, 0, '2018-11-21', '中国大陆、中国香港', '../upload/movies/扫毒.jpg', 0);\r\nINSERT INTO `movie` VALUES (20, '流浪地球', 'The Wandering Earth', '吴京:刘培强,屈楚萧:刘启', '郭帆', '近未来，科学家们发现太阳急速衰老膨胀，短时间内包括地球在内的整个太阳系都将被太阳所吞没。为了自救，人类提出一个名为“流浪地球”的大胆计划，即倾全球之力在地球表面建造上万座发动机和转向发动机，推动地球离开太阳系，用2500年的时间奔往另外一个栖息之地。中国航天员刘培强在儿子刘启四岁那年前往国际空间站，和国际同侪肩负起领航者的重任。转眼刘启长大，他带着妹妹朵朵偷偷跑到地表，偷开外公韩子昂的运输车，结果不仅遭到逮捕，还遭遇了全球发动机停摆的事件。为了修好发动机，阻止地球坠入木星，全球开始展开饱和式营救，连刘启他们的车也被强征加入。在与时间赛跑的过程中，无数的人前仆后继，奋不顾身，只为延续百代子孙生存的希望…… 本片根据刘慈欣的同名小说改编。', '125分钟', '剧情,冒险,科幻', 9.2, 1.0000, 1, '2019-07-05', '中国大陆、中国香港', '../upload/movies/流浪地球.jpg', 1);\r\nINSERT INTO `movie` VALUES (21, '九龙不败', 'The Invincible Dragon', '张晋:九龙', '陈果', '警探九龙（张晋 饰），查案方式奇异狠辣却屡建奇功，是叱咤香港警界的精英干探, 但他处事独断爆裂，又被警队视为“偏执狂人”。九龙奉命调查一桩妙龄女警连环被凶杀 案，用尽手段后不仅毫无线索, 他的警花未婚妻方宁（邓丽欣 饰）竟然也在这场抓捕行动中意外失踪。在爱与痛的边缘挣扎的九龙，突然发现女警连环遇害只是第一步，凶手还有着更加血腥的阴谋，自己和未婚妻竟然也被算计其中。此时澳门再度发生女警被杀案，这次的作案手法更加令人发指，但凶手好像故意留下了线索，是危险陷阱还是复仇曙光？九龙义无反顾出发，在好友王梦奇（刘心悠 饰）及国际拳王冼力山（安德森·席尔瓦 饰）的协助下, 与澳门警司曹志德（郑嘉颖 饰）联手展开调查。魔高一丈，道高几何！血债血偿之前，就算流干最后一滴血，也要誓不罢休。', '100分钟', '剧情,动作,犯罪', 5.7, 1.0000, 1, '2019-07-02', '中国大陆、中国香港', '../upload/movies/九龙不败.jpg', 1);\r\nINSERT INTO `movie` VALUES (22, '阿丽塔：战斗天使', 'Alita: Battle Angel', '罗莎·萨拉查:阿丽塔,克里斯托弗·沃尔兹:戴森·艾德博士', '罗伯特·罗德里格兹', '未来26世纪，科技发展，人类与机械改造人共存，弱肉强食是钢铁城唯一的生存法则。依德（克里斯托夫·沃尔兹 饰）是钢铁城著名的改造人医生，他在垃圾场发现了一个半机械少女残躯，依德医生将其拯救后为她取名阿丽塔（罗莎·萨拉扎尔 饰）。阿丽塔虽然重获生命却失去了记忆，如一个新生儿一样对这个世界充满新鲜感。在依德医生与好友雨果（基恩·约翰逊 饰）的帮助下，她逐步适应着新生活和街头险恶。一次偶然的机会，阿丽塔发现自己竟有着惊人的战斗天赋。 一次次猎杀激发着她的觉醒，阿丽塔逐渐明白自己注定为战斗而生，为正义而战。一场揭开自己身世之谜，并打破宇宙旧秩序的史诗级冒险之旅就这样展开。', '122分钟', '动作,冒险,科幻', 9.0, 1.0000, 0, '2019-07-11', '美国', '../upload/movies/阿丽塔：战斗天使.jpg', 1);\r\nINSERT INTO `movie` VALUES (23, 'X战警：黑凤凰', 'X-Men: Dark Phoenix', '苏菲·特纳:琴·格雷/黑凤凰,詹姆斯·麦卡沃伊:查尔斯·泽维尔/X教授', '西蒙·金伯格', '在一次危及生命的太空营救行动中，琴·葛蕾（苏菲·特纳 饰）被神秘的宇宙力量击中，成为最强大的变种人。此后琴不仅要设法掌控日益增长、极不稳定的力量，更要与自己内心的恶魔抗争，她的失控让整个X战警大家庭分崩离析，也让整个星球陷入毁灭的威胁之中……', '114分钟', '动作,冒险,科幻', 7.8, 1.0000, 0, '2019-06-06', '美国', '../upload/movies/X战警：黑凤凰.jpg', 0);\r\nINSERT INTO `movie` VALUES (24, '疯狂的外星人', 'Crazy Alien', '黄渤:耿浩,沈腾:大飞,马修·莫里森:扎克,汤姆·派福瑞:约翰', '宁浩', '耿浩（黄渤 饰）与一心想发大财的好兄弟大飞（沈腾 饰），经营着各自惨淡的“事业”，然而“天外来客”（徐峥 饰）的意外降临，打破了二人平静又拮据的生活。神秘的西方力量也派出“哼哈二将”在全球搜查外星人行踪。啼笑皆非的跨物种对决，别开生面的“星战”，在中国某海边城市激情上演。', '116分钟', '剧情,喜剧,科幻', 8.5, 1.0000, 0, '2019-07-10', '中国大陆、美国', '../upload/movies/疯狂的外星人.jpg', 1);\r\nINSERT INTO `movie` VALUES (25, '八子', 'ADVANCE WAVE UPON WAVE', '刘端端:满崽,邵兵:大牛', '高希希', '上世纪30年代的赣南地区，在这个被称为中国革命“红色摇篮”的地方，曾经有这样一位母亲，她将八个儿子先后送入红军，奔赴战场前线。但战火无情，兄弟中的六人陆续牺牲，只剩下大哥杨大牛和最小的孩子满崽。满崽找到了大牛的部队，成了哥哥麾下的普通一兵，经过一场场战役的淬炼，新兵满崽迅速成长为一个真正的战士。最后的战斗打响了，为了掩护大部队安全撤离，杨大牛带领弟弟满崽和全体战友浴血肉搏，直至弹尽粮绝…… 英雄的身前，是枪林弹雨的沙场，而在英雄的身后，家乡的村庄依然宁静安详，微风吹过金黄的稻浪簌簌作响，一位年迈的母亲正在村头的小路旁孤独的守望……', '121分钟', '战争,历史,动作', 8.4, 1.0118, 0, '2019-06-30', '中国大陆', '../upload/movies/bazi.jpg', 1);\r\nINSERT INTO `movie` VALUES (26, '我的青春都是你', 'Love The Way You Are', '宋威龙:方予可,宋芸桦:周林林,林妍柔:茹婷,黄俊捷:谢端西,金士杰:畜牧系老师', '周彤', '周林林（宋芸桦 饰）高考发挥超常进入东方大学，与同校理科状元方予可（宋威龙 饰）一同进入了最高学府。郎有情妾无意，方予可其实从幼儿园时期就心系周林林，人生若只如初见，儿时的初遇相见便立下了日久的暗恋情愫！但万人瞩目的帅哥方予可身边有天之骄女茹庭（林妍柔 饰），从小暗恋状元对周林林看不顺眼，周林林则对方予可身边的同为校园风云人物的小西学长（黄俊捷 饰）心存爱慕，修习大学恋爱秘籍，苦练恋爱通关技巧，十八般武艺七十二变法轮番上阵！四人之间情感纠葛，在校园里上演了一幕青春爱情喜剧！', '92分钟', '爱情,青春', 7.3, 1.0000, 1, '2019-06-21', '中国大陆、中国台湾', '../upload/movies/我的青春都是你.jpg', 1);\r\nINSERT INTO `movie` VALUES (27, '银河补习班', 'Looking up', '邓超:马皓文,白宇:成年马飞', '俞白眉', '浩瀚太空，航天员意外失联，生命最大的绝境中，他回忆起自己那个最了不起的爸爸。一对父子跨越漫长的时光，守护爱和亲情，故事充满了欢乐、温暖、泪水与奇观。', '147分钟', '剧情,家庭', 9.1, 1.0200, 0, '2019-07-18', '中国大陆', '../upload/movies/银河补习班.jpg', 1);\r\nINSERT INTO `movie` VALUES (28, '12', '123', '123:13', '123', '1231', '123', '123', 6.1, 0.0000, 0, '2020-02-07', '123', '/upload/movies/9b3caf065b044c01b9e0aedc24a4b80a.jpg', 0);\r\n\r\n-- ----------------------------\r\n-- Table structure for orderinfo\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `orderinfo`;\r\nCREATE TABLE `orderinfo`  (\r\n  `order_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单编号',\r\n  `user_id` bigint(10) NOT NULL COMMENT '所属用户编号',\r\n  `schedule_id` bigint(10) NOT NULL COMMENT '所属场次编号',\r\n  `order_position` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影票座位 （x排x座）',\r\n  `order_state` int(10) NOT NULL DEFAULT 1 COMMENT '订单状态 0:退票中 1:已支付 2:退票成功',\r\n  `order_price` int(10) NOT NULL COMMENT '订单价格',\r\n  `order_time` datetime(0) NOT NULL COMMENT '订单支付时间',\r\n  PRIMARY KEY (`order_id`) USING BTREE\r\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of orderinfo\r\n-- ----------------------------\r\nINSERT INTO `orderinfo` VALUES ('2019072100030210', 3, 25, '2排10座', 1, 38, '2019-07-21 07:01:36');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030306', 3, 310, '3排6座', 1, 40, '2019-07-21 14:44:34');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030307', 3, 26, '3排7座', 0, 40, '2019-07-21 07:07:09');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030409', 3, 26, '4排9座', 1, 40, '2019-07-21 07:14:37');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030508', 3, 310, '5排8座', 2, 40, '2019-07-21 14:44:35');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030603', 3, 310, '6排3座', 1, 40, '2019-07-21 14:44:35');\r\nINSERT INTO `orderinfo` VALUES ('2019072100030606', 3, 310, '6排6座', 1, 40, '2019-07-21 14:44:35');\r\nINSERT INTO `orderinfo` VALUES ('2019072100040606', 4, 27, '6排6座', 1, 55, '2019-07-21 08:55:39');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050506', 5, 65, '5排6座', 2, 45, '2019-07-21 08:52:01');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050507', 5, 65, '5排7座', 0, 45, '2019-07-21 08:52:01');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050509', 5, 135, '5排9座', 1, 32, '2019-07-21 08:50:26');\r\nINSERT INTO `orderinfo` VALUES ('2019072100050510', 5, 135, '5排10座', 1, 32, '2019-07-21 08:50:27');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060502', 6, 136, '5排2座', 1, 34, '2019-07-21 08:50:23');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060503', 6, 136, '5排3座', 1, 34, '2019-07-21 08:50:23');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060504', 6, 136, '5排4座', 1, 34, '2019-07-21 08:50:23');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060509', 6, 122, '5排9座', 1, 28, '2019-07-21 08:52:24');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060602', 6, 153, '6排2座', 0, 32, '2019-07-21 08:52:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060603', 6, 153, '6排3座', 1, 32, '2019-07-21 08:52:16');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060604', 6, 103, '6排4座', 0, 35, '2019-07-21 08:53:12');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060605', 6, 103, '6排5座', 1, 35, '2019-07-21 08:53:12');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060606', 6, 103, '6排6座', 1, 35, '2019-07-21 08:53:12');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060703', 6, 65, '7排3座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060704', 6, 65, '7排4座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060705', 6, 65, '7排5座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060706', 6, 65, '7排6座', 1, 45, '2019-07-21 08:50:45');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060709', 6, 122, '7排9座', 0, 28, '2019-07-21 08:52:25');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060803', 6, 158, '8排3座', 0, 35, '2019-07-21 08:51:30');\r\nINSERT INTO `orderinfo` VALUES ('2019072100060804', 6, 158, '8排4座', 0, 35, '2019-07-21 08:51:31');\r\nINSERT INTO `orderinfo` VALUES ('2020020600030208', 3, 27, '2排8座', 1, 55, '2020-02-06 15:25:29');\r\nINSERT INTO `orderinfo` VALUES ('2020020600030312', 3, 30, '3排12座', 1, 55, '2020-02-06 15:52:15');\r\nINSERT INTO `orderinfo` VALUES ('2020020600030410', 3, 30, '4排10座', 1, 55, '2020-02-06 15:52:15');\r\n\r\n-- ----------------------------\r\n-- Table structure for schedule\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `schedule`;\r\nCREATE TABLE `schedule`  (\r\n  `schedule_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '场次编号',\r\n  `hall_id` bigint(10) NOT NULL COMMENT '所属放映厅编号',\r\n  `movie_id` bigint(10) NOT NULL COMMENT '所属电影编号',\r\n  `schedule_startTime` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '电影放映时间',\r\n  `schedule_price` int(10) NOT NULL COMMENT '场次价格',\r\n  `schedule_remain` int(10) NOT NULL COMMENT '剩余座位数 默认=hall_capacity',\r\n  `schedule_state` int(10) NOT NULL DEFAULT 1 COMMENT '场次状态 默认1 1：上映中 0：下架',\r\n  PRIMARY KEY (`schedule_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 315 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of schedule\r\n-- ----------------------------\r\nINSERT INTO `schedule` VALUES (25, 1, 25, '2019-07-21 17:30', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (26, 7, 25, '2019-07-22 20:00', 40, 143, 1);\r\nINSERT INTO `schedule` VALUES (27, 7, 1, '2019-07-21 19:10', 55, 142, 1);\r\nINSERT INTO `schedule` VALUES (28, 8, 25, '2019-07-23 17:00', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (29, 1, 20, '2019-07-21 00:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (30, 13, 1, '2019-07-22 19:20', 55, 142, 1);\r\nINSERT INTO `schedule` VALUES (31, 7, 20, '2019-07-21 00:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (32, 13, 20, '2019-07-21 00:00', 38, 144, 0);\r\nINSERT INTO `schedule` VALUES (33, 1, 1, '2019-07-23 20:00', 55, 144, 1);\r\nINSERT INTO `schedule` VALUES (34, 45, 20, '2019-07-22 20:30', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (35, 8, 25, '2019-07-24 00:00', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (36, 7, 1, '2019-07-24 20:10', 55, 144, 1);\r\nINSERT INTO `schedule` VALUES (37, 7, 20, '2019-07-22 15:30', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (38, 8, 20, '2019-07-23 14:20', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (39, 2, 1, '2019-07-21 10:10', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (40, 2, 1, '2019-07-22 10:10', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (41, 8, 20, '2019-07-23 21:45', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (42, 11, 25, '2019-07-23 12:30', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (43, 8, 20, '2019-07-23 10:40', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (44, 29, 25, '2019-07-25 00:00', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (45, 8, 1, '2019-07-23 10:20', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (46, 2, 20, '2019-07-22 19:30', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (47, 8, 1, '2019-07-24 10:20', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (48, 37, 25, '2019-07-23 20:00', 38, 144, 0);\r\nINSERT INTO `schedule` VALUES (49, 45, 20, '2019-07-23 20:20', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (50, 7, 20, '2019-07-23 16:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (51, 46, 20, '2019-07-23 15:15', 68, 144, 1);\r\nINSERT INTO `schedule` VALUES (52, 3, 1, '2019-07-23 10:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (53, 14, 20, '2019-07-24 13:00', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (54, 46, 1, '2019-07-23 19:20', 67, 144, 1);\r\nINSERT INTO `schedule` VALUES (55, 29, 20, '2019-07-24 17:10', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (56, 9, 1, '2019-07-24 09:40', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (57, 46, 1, '2019-07-24 19:30', 66, 144, 1);\r\nINSERT INTO `schedule` VALUES (58, 32, 20, '2019-07-23 09:30', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (59, 24, 3, '2019-07-25 13:35', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (60, 49, 25, '2019-07-24 10:00', 50, 144, 1);\r\nINSERT INTO `schedule` VALUES (61, 37, 20, '2019-07-23 22:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (62, 5, 1, '2019-07-23 10:15', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (63, 51, 3, '2019-07-23 17:05', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (64, 36, 25, '2019-07-23 19:30', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (65, 35, 3, '2019-07-24 19:05', 45, 138, 1);\r\nINSERT INTO `schedule` VALUES (66, 29, 20, '2019-07-24 07:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (67, 4, 26, '2019-07-23 20:00', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (68, 16, 3, '2019-07-23 18:05', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (69, 10, 20, '2019-07-24 13:35', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (70, 33, 26, '2019-07-24 21:00', 22, 144, 1);\r\nINSERT INTO `schedule` VALUES (71, 4, 1, '2019-07-23 09:45', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (72, 10, 1, '2019-07-23 19:20', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (73, 24, 3, '2019-07-25 21:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (74, 11, 21, '2019-07-23 14:15', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (75, 23, 26, '2019-07-24 13:00', 25, 144, 1);\r\nINSERT INTO `schedule` VALUES (76, 4, 1, '2019-07-24 09:50', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (77, 31, 3, '2019-07-26 12:45', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (78, 37, 26, '2019-07-24 19:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (79, 11, 21, '2019-07-23 15:25', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (80, 10, 1, '2019-07-24 20:00', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (81, 10, 26, '2019-07-23 22:05', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (82, 39, 21, '2019-07-23 20:05', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (83, 11, 1, '2019-07-23 21:10', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (84, 5, 21, '2019-07-24 10:20', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (85, 24, 26, '2019-07-24 17:30', 25, 144, 1);\r\nINSERT INTO `schedule` VALUES (86, 31, 26, '2019-07-22 19:00', 28, 144, 1);\r\nINSERT INTO `schedule` VALUES (87, 5, 1, '2019-07-24 09:30', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (88, 11, 21, '2019-07-24 22:15', 36, 144, 1);\r\nINSERT INTO `schedule` VALUES (89, 17, 26, '2019-07-22 00:00', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (90, 35, 3, '2019-07-24 18:40', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (91, 39, 1, '2019-07-24 20:25', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (92, 12, 21, '2019-07-23 14:10', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (93, 12, 26, '2019-07-23 22:00', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (94, 24, 5, '2019-07-21 19:55', 54, 144, 1);\r\nINSERT INTO `schedule` VALUES (95, 12, 21, '2019-07-23 16:05', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (96, 6, 1, '2019-07-23 10:20', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (97, 8, 26, '2019-07-23 10:00', 25, 144, 1);\r\nINSERT INTO `schedule` VALUES (98, 47, 24, '2019-07-28 14:45', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (99, 12, 21, '2019-07-24 10:00', 29, 144, 1);\r\nINSERT INTO `schedule` VALUES (100, 6, 1, '2019-07-23 21:10', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (101, 29, 26, '2019-07-23 20:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (102, 12, 1, '2019-07-24 10:10', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (103, 30, 21, '2019-07-23 13:10', 35, 141, 1);\r\nINSERT INTO `schedule` VALUES (104, 12, 1, '2019-07-24 20:40', 46, 144, 1);\r\nINSERT INTO `schedule` VALUES (105, 30, 21, '2019-07-23 21:05', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (106, 25, 26, '2019-07-24 23:00', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (107, 28, 21, '2019-07-24 16:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (108, 14, 1, '2019-07-23 19:20', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (109, 1, 15, '2019-07-23 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (110, 26, 1, '2019-07-24 10:20', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (111, 51, 22, '2019-07-21 00:00', 59, 144, 1);\r\nINSERT INTO `schedule` VALUES (112, 40, 1, '2019-07-24 22:00', 44, 144, 1);\r\nINSERT INTO `schedule` VALUES (113, 4, 18, '2019-07-25 08:05', 65, 144, 1);\r\nINSERT INTO `schedule` VALUES (114, 36, 22, '2019-07-21 00:00', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (115, 34, 22, '2019-07-23 13:15', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (116, 31, 22, '2019-07-23 13:20', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (117, 16, 17, '2019-07-24 09:10', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (118, 15, 1, '2019-07-23 20:30', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (119, 27, 1, '2019-07-24 09:50', 43, 144, 1);\r\nINSERT INTO `schedule` VALUES (120, 47, 18, '2019-07-25 16:30', 54, 144, 1);\r\nINSERT INTO `schedule` VALUES (121, 47, 1, '2019-07-24 20:40', 56, 144, 1);\r\nINSERT INTO `schedule` VALUES (122, 43, 18, '2019-07-24 04:25', 28, 142, 1);\r\nINSERT INTO `schedule` VALUES (123, 1, 15, '2019-07-21 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (124, 16, 1, '2019-07-23 21:20', 41, 144, 1);\r\nINSERT INTO `schedule` VALUES (125, 34, 18, '2019-07-21 17:15', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (126, 7, 15, '2019-07-22 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (127, 28, 1, '2019-07-24 20:30', 41, 144, 1);\r\nINSERT INTO `schedule` VALUES (128, 17, 1, '2019-07-23 14:15', 42, 144, 1);\r\nINSERT INTO `schedule` VALUES (129, 1, 15, '2019-07-21 20:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (130, 29, 1, '2019-07-24 09:00', 42, 144, 1);\r\nINSERT INTO `schedule` VALUES (131, 7, 15, '2019-07-22 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (132, 36, 22, '2019-07-24 16:20', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (133, 3, 16, '2019-07-24 10:10', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (134, 13, 15, '2019-07-23 10:30', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (135, 25, 4, '2019-07-21 05:25', 32, 142, 1);\r\nINSERT INTO `schedule` VALUES (136, 1, 2, '2019-07-23 10:05', 34, 141, 1);\r\nINSERT INTO `schedule` VALUES (137, 13, 15, '2019-07-23 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (138, 7, 2, '2019-07-23 22:15', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (139, 48, 22, '2019-07-24 15:25', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (140, 49, 23, '2019-07-21 15:15', 42, 144, 1);\r\nINSERT INTO `schedule` VALUES (141, 13, 15, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (142, 30, 22, '2019-07-23 16:15', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (143, 7, 15, '2019-07-24 18:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (144, 13, 2, '2019-07-24 17:10', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (145, 7, 15, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (146, 25, 2, '2019-07-23 19:30', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (147, 40, 23, '2019-07-23 10:30', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (148, 37, 2, '2019-07-24 10:05', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (149, 26, 23, '2019-07-23 20:15', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (150, 44, 2, '2019-07-24 19:10', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (151, 24, 2, '2019-07-22 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (152, 32, 23, '2019-07-23 13:30', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (153, 36, 2, '2019-07-23 00:00', 32, 142, 1);\r\nINSERT INTO `schedule` VALUES (154, 51, 2, '2019-07-24 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (155, 10, 23, '2019-07-23 13:20', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (156, 2, 15, '2019-07-21 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (157, 33, 23, '2019-07-23 19:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (158, 23, 2, '2019-07-23 09:00', 35, 142, 1);\r\nINSERT INTO `schedule` VALUES (159, 2, 15, '2019-07-21 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (160, 35, 2, '2019-07-24 21:00', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (161, 8, 15, '2019-07-21 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (162, 50, 2, '2019-07-25 20:05', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (163, 8, 15, '2019-07-21 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (164, 22, 2, '2019-07-22 00:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (165, 27, 23, '2019-07-23 16:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (166, 2, 15, '2019-07-21 20:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (167, 34, 2, '2019-07-23 00:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (168, 43, 2, '2019-07-24 00:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (169, 47, 24, '2019-07-23 16:10', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (170, 2, 15, '2019-07-23 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (171, 28, 24, '2019-07-23 15:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (172, 8, 15, '2019-07-23 10:30', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (173, 29, 24, '2019-07-21 15:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (174, 20, 3, '2019-07-23 09:00', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (175, 8, 15, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (176, 32, 3, '2019-07-24 12:15', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (177, 34, 24, '2019-07-24 10:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (178, 8, 15, '2019-07-24 13:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (179, 4, 3, '2019-07-23 15:00', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (180, 8, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (181, 10, 3, '2019-07-24 17:00', 27, 144, 1);\r\nINSERT INTO `schedule` VALUES (182, 3, 15, '2019-07-22 09:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (183, 42, 24, '2019-07-24 13:35', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (184, 25, 3, '2019-07-22 08:00', 26, 144, 1);\r\nINSERT INTO `schedule` VALUES (185, 3, 15, '2019-07-22 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (186, 9, 15, '2019-07-22 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (187, 38, 15, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (188, 37, 3, '2019-07-24 14:05', 26, 144, 1);\r\nINSERT INTO `schedule` VALUES (189, 35, 24, '2019-07-24 16:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (190, 38, 15, '2019-07-25 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (191, 44, 3, '2019-07-25 09:00', 26, 144, 1);\r\nINSERT INTO `schedule` VALUES (192, 3, 15, '2019-07-25 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (193, 1, 4, '2019-07-22 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (194, 7, 4, '2019-07-23 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (195, 35, 24, '2019-07-24 16:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (196, 4, 15, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (197, 13, 4, '2019-07-24 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (198, 10, 15, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (199, 45, 4, '2019-07-25 23:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (200, 10, 15, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (201, 20, 4, '2019-07-23 23:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (202, 10, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (203, 20, 4, '2019-07-24 23:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (204, 5, 15, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (205, 4, 4, '2019-07-23 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (206, 10, 4, '2019-07-24 00:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (207, 11, 15, '2019-07-23 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (208, 16, 21, '2019-07-23 13:25', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (209, 39, 15, '2019-07-23 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (210, 5, 15, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (211, 11, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (212, 37, 4, '2019-07-23 15:05', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (213, 22, 22, '2019-07-23 16:05', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (214, 44, 4, '2019-07-24 14:10', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (215, 6, 15, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (216, 24, 5, '2019-07-23 04:00', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (217, 12, 15, '2019-07-23 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (218, 12, 15, '2019-07-24 09:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (219, 42, 22, '2019-07-24 17:00', 48, 144, 1);\r\nINSERT INTO `schedule` VALUES (220, 6, 15, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (221, 1, 16, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (222, 36, 5, '2019-07-21 14:54', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (223, 13, 16, '2019-07-23 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (224, 20, 23, '2019-07-24 18:45', 40, 144, 1);\r\nINSERT INTO `schedule` VALUES (225, 15, 5, '2019-07-23 04:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (226, 7, 16, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (227, 42, 5, '2019-07-24 04:00', 34, 144, 1);\r\nINSERT INTO `schedule` VALUES (228, 7, 16, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (229, 4, 23, '2019-07-24 14:15', 39, 144, 1);\r\nINSERT INTO `schedule` VALUES (230, 27, 5, '2019-07-23 05:05', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (231, 13, 15, '2019-07-24 18:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (232, 2, 16, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (233, 47, 23, '2019-07-23 20:15', 58, 144, 1);\r\nINSERT INTO `schedule` VALUES (234, 2, 16, '2019-07-23 16:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (235, 2, 16, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (236, 15, 23, '2019-07-24 20:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (237, 8, 16, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (238, 11, 5, '2019-07-24 14:57', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (239, 2, 16, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (240, 27, 5, '2019-07-21 14:58', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (241, 41, 5, '2019-07-24 07:00', 32, 144, 1);\r\nINSERT INTO `schedule` VALUES (242, 16, 24, '2019-07-23 20:05', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (243, 3, 16, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (244, 22, 5, '2019-07-22 05:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (245, 38, 16, '2019-07-23 19:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (246, 34, 5, '2019-07-23 05:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (247, 9, 15, '2019-07-24 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (248, 41, 24, '2019-07-23 12:00', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (249, 43, 5, '2019-07-24 05:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (250, 9, 16, '2019-07-24 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (251, 17, 24, '2019-07-24 20:15', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (252, 4, 16, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (253, 10, 16, '2019-07-24 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (254, 30, 24, '2019-07-23 14:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (255, 5, 16, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (256, 22, 24, '2019-07-23 14:20', 38, 144, 1);\r\nINSERT INTO `schedule` VALUES (257, 5, 16, '2019-07-23 19:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (258, 5, 16, '2019-07-24 13:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (259, 39, 16, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (260, 6, 16, '2019-07-23 00:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (261, 12, 16, '2019-07-24 16:00', 20, 144, 1);\r\nINSERT INTO `schedule` VALUES (262, 1, 17, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (263, 7, 17, '2019-07-23 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (264, 13, 17, '2019-07-24 07:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (265, 7, 17, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (266, 2, 17, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (267, 8, 17, '2019-07-23 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (268, 2, 17, '2019-07-24 09:20', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (269, 8, 17, '2019-07-24 15:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (270, 3, 17, '2019-07-23 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (271, 9, 17, '2019-07-23 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (272, 38, 17, '2019-07-24 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (273, 4, 17, '2019-07-23 14:00', 20, 144, 1);\r\nINSERT INTO `schedule` VALUES (274, 10, 17, '2019-07-24 14:05', 20, 144, 1);\r\nINSERT INTO `schedule` VALUES (275, 11, 17, '2019-07-23 10:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (276, 11, 17, '2019-07-24 17:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (277, 12, 17, '2019-07-23 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (278, 12, 17, '2019-07-24 11:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (279, 6, 17, '2019-07-23 09:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (280, 39, 17, '2019-07-23 21:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (281, 39, 17, '2019-07-24 00:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (282, 38, 17, '2019-07-24 08:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (283, 1, 18, '2019-07-23 08:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (284, 7, 18, '2019-07-23 12:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (285, 13, 18, '2019-07-24 14:00', 30, 144, 1);\r\nINSERT INTO `schedule` VALUES (286, 1, 18, '2019-07-24 16:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (287, 2, 18, '2019-07-23 17:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (288, 2, 18, '2019-07-23 09:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (289, 2, 18, '2019-07-23 14:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (290, 2, 18, '2019-07-24 10:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (291, 2, 18, '2019-07-24 13:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (292, 3, 18, '2019-07-23 12:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (293, 9, 18, '2019-07-23 20:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (294, 3, 18, '2019-07-23 15:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (295, 9, 18, '2019-07-24 10:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (296, 9, 18, '2019-07-24 11:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (297, 38, 18, '2019-07-24 21:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (298, 10, 18, '2019-07-23 08:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (299, 4, 18, '2019-07-23 11:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (300, 4, 18, '2019-07-24 14:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (301, 10, 18, '2019-07-24 21:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (302, 5, 18, '2019-07-23 08:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (303, 11, 18, '2019-07-24 11:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (304, 39, 18, '2019-07-24 15:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (305, 6, 18, '2019-07-23 10:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (306, 12, 18, '2019-07-24 12:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (307, 12, 18, '2019-07-24 18:00', 33, 144, 1);\r\nINSERT INTO `schedule` VALUES (308, 1, 27, '2019-07-23 00:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (309, 7, 27, '2019-07-24 19:00', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (310, 8, 27, '2019-07-23 20:00', 40, 140, 1);\r\nINSERT INTO `schedule` VALUES (311, 4, 27, '2019-07-23 16:00', 49, 144, 1);\r\nINSERT INTO `schedule` VALUES (312, 11, 27, '2019-07-24 19:15', 45, 144, 1);\r\nINSERT INTO `schedule` VALUES (313, 8, 27, '2019-07-24 15:00', 35, 144, 1);\r\nINSERT INTO `schedule` VALUES (314, 1, 3, '2020-02-11 00:00', 123, 144, 1);\r\n\r\n-- ----------------------------\r\n-- Table structure for user\r\n-- ----------------------------\r\nDROP TABLE IF EXISTS `user`;\r\nCREATE TABLE `user`  (\r\n  `user_id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '会员编号',\r\n  `user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '会员账号',\r\n  `user_pwd` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '会员密码',\r\n  `user_email` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '会员邮箱',\r\n  `user_role` int(10) NOT NULL DEFAULT 0 COMMENT '会员权限（默认为0）\\r\\n0：普通会员 1：管理员',\r\n  `user_headImg` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '会员头像',\r\n  PRIMARY KEY (`user_id`) USING BTREE\r\n) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\r\n\r\n-- ----------------------------\r\n-- Records of user\r\n-- ----------------------------\r\nINSERT INTO `user` VALUES (1, 'user', 'user', '337872621@qq.com', 0, NULL);\r\nINSERT INTO `user` VALUES (2, 'admin', 'admin', '3456872621@qq.com', 1, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (3, 'wxj', '1234', '937872111@126.com', 1, '/upload/head/355f887b0ee8493a8070c89dcdcf1789.jpg');\r\nINSERT INTO `user` VALUES (4, 'lpf', 'lpf', '23546211543@qq.com', 0, '../upload/head/85c888cf36d649d6aaea58f19cc8c143.jpg');\r\nINSERT INTO `user` VALUES (5, 'wzw', 'wzw', '2154698421@126.com', 0, '../upload/head/bdc1cf2d9b9d4d5ca5d7a34f2ebfc5b3.jpg');\r\nINSERT INTO `user` VALUES (6, 'hzw', 'hzw', 'a487953215@163.com', 0, '../upload/head/demo.jpg');\r\nINSERT INTO `user` VALUES (7, 'lsw', 'lsw', '3215644123@qq.com', 0, '../upload/head/84c69b60d91e4c079e249a6cd09ef91c.jpg');\r\nINSERT INTO `user` VALUES (8, 'bg12356484', '6484', '910050724@qq.com', 0, '../upload/head/demo.jpg');\r\nINSERT INTO `user` VALUES (9, 'ao13546954', '6954', 'hsw236413512@163.com', 0, NULL);\r\nINSERT INTO `user` VALUES (19, 'jd15154478', '4478', '5648132142@163.com', 0, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (20, 'sn46845411', '5411', 'gs15648231@126.com', 0, '../upload/head/84c69b60d91e4c079e249a6cd09ef91c.jpg');\r\nINSERT INTO `user` VALUES (21, 'gs12314864', '4864', '2154678122@qq.com', 0, '../upload/head/84c69b60d91e4c079e249a6cd09ef91c.jpg');\r\nINSERT INTO `user` VALUES (22, 'jd12315164', '5164', '211215484@qq.com', 0, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (23, 'kl15645641', '5641', 'g123456412@163.com', 0, '../upload/head/dd7cf74e264247ffbe888c4e163fb9ed.jpg');\r\nINSERT INTO `user` VALUES (24, 'kd1231854', '1854', '123484547@qq.com', 0, NULL);\r\nINSERT INTO `user` VALUES (25, 'tw1123484', '3484', '988744641@qq.com', 0, '../upload/head/dc56255b1e4f4ad4b0a76a8eb0fc7f45.jpg');\r\nINSERT INTO `user` VALUES (26, 'if48648411', '8411', 'u365484741@163.com', 0, '../upload/head/dd7cf74e264247ffbe888c4e163fb9ed.jpg');\r\nINSERT INTO `user` VALUES (27, 'od1561487', '1487', '1564562314@qq.com', 0, NULL);\r\nINSERT INTO `user` VALUES (28, 'jd54687233', '7233', '165484754@qq.com', 0, NULL);\r\nINSERT INTO `user` VALUES (29, 'test', '123', '123', 0, NULL);\r\n\r\nSET FOREIGN_KEY_CHECKS = 1;\r\n"
  },
  {
    "path": "src/main/resources/mybatis.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<!-- 定义别名 -->\n\t<typeAliases>\n\t\t<package name=\"com.mapper\"/>\n\t</typeAliases>\n\t\n\t<!-- 配置 mybatis的分页插件 -->\n\t<plugins>\n\t\t<!-- com.github.pagehelper 为 PageHelper类所在包名 -->\n\t\t<plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n\t\t\t<!-- 分页参数合理化，默认为false。\n\t\t\t  启动合理化时，如果pageNum < 1 会查询第一页，\n\t\t\t  如果pageNum > pages 会查询最后一页；\n\t\t\t禁用合理化时，如果pageNum < 1或pageNum > pages会返回空数据。 -->\n\t\t\t<property name=\"reasonable\" value=\"true\"/>\n\t\t\t<!-- 设置数据库类型Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreS -->\n\t\t\t<property name=\"helpetrDialect\" value=\"mysql\"/>\n\t\t</plugin>\n\t</plugins>\n\t<!-- mapper映射 -->\n\t<mappers>\n\t\t<package name=\"com.mapper\"/>\n\t</mappers>\n\t\n</configuration>"
  },
  {
    "path": "src/main/resources/mysql.properties",
    "content": "driver=com.mysql.cj.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/movie?serverTimezone=UTC\nusername=root\npassword=root"
  },
  {
    "path": "src/main/resources/spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\" xmlns:mvc=\"http://www.springframework.org/schema/mvc\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:p=\"http://www.springframework.org/schema/p\" xmlns:mongo=\"http://www.springframework.org/schema/data/mongo\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/data/mongo \n\t\thttp://www.springframework.org/schema/data/mongo/spring-mongo-1.8.xsd\n\t\thttp://www.springframework.org/schema/aop \n\t\thttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd\n\t\thttp://www.springframework.org/schema/mvc\n\t\thttp://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd\n\t\thttp://www.springframework.org/schema/beans \n\t\thttp://www.springframework.org/schema/beans/spring-beans-4.0.xsd\n\t\thttp://www.springframework.org/schema/tx \n\t\thttp://www.springframework.org/schema/tx/spring-tx-4.0.xsd\n\t\thttp://www.springframework.org/schema/context \n\t\thttp://www.springframework.org/schema/context/spring-context-4.0.xsd\">\n\t\t\n\t<!-- 引入属性文件，获取配置参数 -->\n    <bean id=\"propertyConfigurer\" class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">  \n\t\t<property name=\"location\" value=\"classpath:mysql.properties\" /> \n\t</bean>\n\t\n\t <!-- 使用阿里巴巴的数据库连接池 -->\n\t<bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\"  destroy-method=\"close\">  \n\t\t<property name=\"driverClassName\" value=\"${driver}\" />  \n\t\t<property name=\"url\" value=\"${url}\" />  \n\t\t<property name=\"username\" value=\"${username}\" />  \n\t\t<property name=\"password\" value=\"${password}\" /> \n\t\t<!-- 连接池参数 --> \n\t\t<property name=\"maxActive\" value=\"800\"/>\n       \t<property name=\"minIdle\" value=\"10\"/>\n\t</bean>  \n\t\n\t<!-- 注册sqlSessionFactoryBean -->\n\t<!-- spring和MyBatis完美整合，不需要单独配置mybatis的映射文件 -->\t\n\t<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<!-- 指定数据源  连接池 -->\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t\t<!-- 指定 mybatis 主配置文件 -->\n\t\t<property name=\"configLocation\" value=\"classpath:mybatis.xml\"/>\n\t</bean>\n\t\n\t<!-- Mapper接口所在的包名，Spring会自动找到其下的类 -->\n\t<!-- 生产dao代理对象 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<property name=\"basePackage\" value=\"com.mapper\" />\n\t\t<property name=\"sqlSessionFactoryBeanName\" value=\"sqlSessionFactory\"></property>\n\t</bean>\n\t\n\t<!-- 注册事务管理器 -->\n\t<bean id=\"transactionManager\"  class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\t\n\t<!--支持注解驱动的事务管理，指定事务管理器 -->\n   \t<tx:annotation-driven transaction-manager=\"transactionManager\"/>\n   \t\n   \t<!--自动扫描IOC组件  -->\n    <context:component-scan base-package=\"com\"></context:component-scan>\n \t\n \t<!-- 开启aspectj代理 -->\n \t<aop:aspectj-autoproxy/>\n \t\n \t\n\t<!-- Jackson配置-->\n\t<bean id=\"objectMapper\" class=\"com.fasterxml.jackson.databind.ObjectMapper\">\n\t\t<property name=\"serializationInclusion\" value=\"NON_NULL\" />\n\t\t<property name=\"dateFormat\">\n\t\t\t<bean class=\"java.text.SimpleDateFormat\">\n\t\t\t\t<constructor-arg value=\"yyyy-MM-dd HH:mm:ss\" />\n\t\t\t</bean>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 注解映射支持；JSON转换器 -->\n\t<mvc:annotation-driven>\n\t\t<mvc:message-converters register-defaults=\"true\">\n\t\t\t<bean class=\"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter\">\n\t\t\t\t<property name=\"objectMapper\" ref=\"objectMapper\" />\n\t\t\t\t<property name=\"supportedMediaTypes\">\n\t\t\t\t\t<list>\n\t\t\t\t\t\t<value>text/plain;charset=UTF-8</value>\n\t\t\t\t\t\t<value>application/json;charset=UTF-8</value>\n\t\t\t\t\t</list>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t\t<!-- 对于字符串类型解析的配置 -->\n\t\t\t<bean class=\"org.springframework.http.converter.StringHttpMessageConverter\">  \n            \t<property name=\"supportedMediaTypes\" value = \"text/html;charset=UTF-8\" />  \n        \t</bean> \t\t\n\t\t</mvc:message-converters>\n\t</mvc:annotation-driven>\n\t\n\t<!-- freemarker的配置 -->\n\t<bean id=\"freemarkerConfig\" class=\"org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer\">\n\t\t<property name=\"templateLoaderPath\" value=\"/views/\" />\n\t\t<property name=\"defaultEncoding\" value=\"utf-8\" />\n\t\t<property name=\"freemarkerSettings\">\n\t\t\t<props>\n\t\t\t\t<prop key=\"default_encoding\">UTF-8</prop>\n\t\t\t\t<prop key=\"output_encoding\">UTF-8</prop>\n\t\t\t\t<prop key=\"template_update_delay\">10</prop>\n\t\t\t\t<prop key=\"locale\">zh_CN</prop>\n\t\t\t\t<prop key=\"datetime_format\">yyyy-MM-dd HH:mm</prop>\n\t\t\t\t<prop key=\"date_format\">yyyy-MM-dd</prop>\n\t\t\t\t<prop key=\"time_format\">HH:mm:ss</prop>\n\t\t\t\t<prop key=\"number_format\">#.##</prop>\n\t\t\t</props>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- FreeMarker视图解析 -->\n\t<bean id=\"viewResolver\" class=\"org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver\">\n\t\t<property name=\"viewClass\" value=\"org.springframework.web.servlet.view.freemarker.FreeMarkerView\"></property>\n\t\t<property name=\"suffix\" value=\".html\" />\n\t\t<property name=\"contentType\" value=\"text/html;charset=utf-8\" />\n\t\t<property name=\"exposeRequestAttributes\" value=\"true\" />\n\t\t<property name=\"exposeSessionAttributes\" value=\"true\" />\n\t\t<property name=\"exposeSpringMacroHelpers\" value=\"true\" />\n\t\t<property name=\"cache\" value=\"false\" />\n\t\t<property name=\"requestContextAttribute\" value=\"rc\"></property>\n\t</bean>\n\t\n\t<!-- 文件解析器 -->\n\t<bean id=\"multipartResolver\" class=\"org.springframework.web.multipart.commons.CommonsMultipartResolver\">\n\t\t<property name=\"maxUploadSize\" value=\"1100000\"></property>\n\t\t<property name=\"defaultEncoding\" value=\"UTF-8\"></property>\n\t</bean>\n</beans>"
  },
  {
    "path": "src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n         xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" \n         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" \n         id=\"WebApp_ID\" version=\"3.1\">\n\t<display-name>Movie</display-name>\n  \t<welcome-file-list>\n  \t\t<welcome-file>index.html</welcome-file>\n  \t\t<welcome-file>test.jsp</welcome-file>\n  \t</welcome-file-list>\n  \t\n\t<!-- 注册spring配置文件的位置 -->\n\t<context-param>\n\t\t<param-name>contextConfigLocation</param-name>\n\t\t<param-value>classpath:spring.xml</param-value>\n\t</context-param>\n  \n\t<!-- 注册serverContext监听器，创建Spring容器 -->\n\t<listener>\n\t\t<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n\t</listener>\n\t\n\t<!-- 配置字符过滤器 -->\n\t<filter>\n\t\t<filter-name>characterEncodingFilter</filter-name>\n\t\t<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>\n\t\t<!-- 指定字符集 -->\n\t\t<init-param>\n\t\t\t<param-name>encoding</param-name>\n\t\t\t<param-value>utf-8</param-value>\n\t\t</init-param>\n\t\t<!-- 指定强制使用指定的字符集 -->\n\t\t<init-param>\n\t\t\t<param-name>forceEncoding</param-name>\n\t\t\t<param-value>true</param-value>\n\t\t</init-param>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>characterEncodingFilter</filter-name>\n\t\t<url-pattern>/*/</url-pattern>\n\t</filter-mapping>\n\t<!-- 中央调度器 所有请求都由DispatcherServlet处理 -->\n\t<servlet>\n\t\t<servlet-name>springmvc</servlet-name>\n\t\t<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>\n\t\t<init-param>\n\t\t\t<param-name>contextConfigLocation</param-name>\n\t\t\t<param-value>classpath:spring.xml</param-value>\n\t\t</init-param>\n\t\t<!--在tomcat 启动时直接创建当前servlet 对象，放置一个大于0 的整数-->\n\t\t<load-on-startup>1</load-on-startup>\n\t</servlet>\n\t<servlet-mapping>\n\t\t<servlet-name>springmvc</servlet-name>\n\t\t<!-- 拦截所有请求-->\n\t\t<url-pattern>/</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.js</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.css</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.jpg</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.JPG</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.jpeg</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.png</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.eot</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.svg</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.ttf</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.woff</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.woff2</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.gif</url-pattern>\n\t</servlet-mapping>\n\t<servlet-mapping>\n\t\t<servlet-name>default</servlet-name>\n\t\t<url-pattern>*.ico</url-pattern>\n\t</servlet-mapping>\n\t<!-- 使用Rest 风格的URI，将页面普通的post 请求转为指定的delete 或者put请求-->\n\t<filter>\n\t\t<filter-name>HiddenHttpMethodFilter</filter-name>\n\t\t<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>HiddenHttpMethodFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\t<filter>\n\t\t<filter-name>HttpPutFormContentFilter</filter-name>\n\t\t<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>HttpPutFormContentFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\t\n\t<!-- 跨域配置-->    \n\t<filter>\n        <!-- The CORS filter with parameters -->\n        <filter-name>CORS</filter-name>\n        <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>\n        \n        <!-- Note: All parameters are options, if omitted the CORS \n             Filter will fall back to the respective default values.\n          -->\n        <init-param>\n            <param-name>cors.allowGenericHttpRequests</param-name>\n            <param-value>true</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.allowOrigin</param-name>\n            <param-value>*</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.allowSubdomains</param-name>\n            <param-value>false</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.supportedMethods</param-name>\n            <param-value>GET, HEAD, POST, OPTIONS</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.supportedHeaders</param-name>\n            <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.exposedHeaders</param-name>\n            <!--这里可以添加一些自己的暴露Headers   -->\n            <param-value>X-Test-1, X-Test-2</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.supportsCredentials</param-name>\n            <param-value>true</param-value>\n        </init-param>\n        \n        <init-param>\n            <param-name>cors.maxAge</param-name>\n            <param-value>3600</param-value>\n        </init-param>\n\n    </filter>\n\n    <filter-mapping>\n        <!-- CORS Filter mapping -->\n        <filter-name>CORS</filter-name>\n        <url-pattern>/*</url-pattern>\n    </filter-mapping>\n</web-app>"
  },
  {
    "path": "src/main/webapp/index.html",
    "content": ""
  },
  {
    "path": "src/main/webapp/jsp/buySeat.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/buySeat.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-选位置</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 90px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"container\">\n        <div class=\"order-progress-bar\">\n            <div class=\"step first done\">\n                <span class=\"step-num\">1</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">选择影片场次</span>\n            </div>\n            <div class=\"step done\">\n                <span class=\"step-num\">2</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">选择座位</span>\n            </div>\n            <div class=\"step\">\n                <span class=\"step-num\">3</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">付款</span>\n            </div>\n            <div class=\"step last\">\n                <span class=\"step-num\">4</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">影院取票观影</span>\n            </div>\n        </div>\n\n        <div class=\"main\">\n            <!-- 主页 -->\n            <div class=\"hall\">\n                <div class=\"seat-example\">\n                    <div class=\"selectable-example example\">\n                        <span>可选座位</span>\n                    </div>\n                    <div class=\"sold-example example\">\n                        <span>已售座位</span>\n                    </div>\n                    <div class=\"selected-example example\">\n                        <span>已选座位</span>\n                    </div>\n                    <div class=\"couple-example example\">\n                        <span>情侣座位</span>\n                    </div>\n                </div>\n                <div class=\"seats-block\">\n                    <div class=\"row-id-container\">\n                    </div>\n                    <div class=\"seats-container\">\n                        <div class=\"screen-container\">\n                            <div class=\"screen\">银幕中央</div>\n                            <div class=\"c-screen-line\"></div>\n                        </div>\n                        <div class=\"seats-wrapper\">\n                        </div>\n                    </div>\n                </div>\n            </div>\n            <!-- 侧页 -->\n            <div class=\"side\">\n                <!-- 电影 -->\n                <div class=\"movie-info clearfix\">\n                </div>\n                <!-- 场次 -->\n                <div class=\"show-info\">\n                    \n                </div>\n                <div class=\"ticket-info\">\n                    <div class=\"no-ticket\" style=\"display: block;\">\n                        <p class=\"buy-limit\">座位：一次最多选4个座位</p>\n                    </div>\n                    <div class=\"has-ticket\" style=\"display: none;\">\n                        <span class=\"text\">座位：</span>\n                        <div class=\"ticket-container\">\n                        </div>\n                    </div>\n                    <div class=\"total-price\">\n                        <span>总价：</span>\n                        <span class=\"price\"></span>\n                    </div>\n                </div>\n                <div class=\"confirm-order\">\n                    <div class=\"email\">\n                        <span>邮箱号：</span>\n                    </div>\n                    <div class=\"confirm-btn disable\" onclick=\"confirm()\">确认选座</div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var SeatMax=0;\n        var PriceTemp=1;\n        var schedule_id = getUrlParams(\"schedule_id\");\n        var TempLength;\n        var TempSeat = \"\";\n        var Seatrow = [], Seatcol = [];\n\n        window.onload = function(){\n            initHeader();\n            initEmail(); //邮箱\n            initInformation(); //信息\n        }\n\n        //初始化邮箱\n        function initEmail(){\n            var user_name;\n            var email = $(\".email\");\n            email.append(\"<span class=\\\"email-num\\\">137***325@qq.com</span>\");\n        }\n\n        //点击具体座位事件  \n        function buySeat(i,j){\n            var row = $(\".seats-wrapper\").find(\".row\")[i].children[j];\n            var flag = 0;\n            var NoTicket = $(\".no-ticket\")[0];\n            var HasTicket = $(\".has-ticket\")[0];\n            var Ticket = $(\".has-ticket\").find(\".ticket-container\");\n            var TicketRemove;\n            var TicketPrice = $(\".price\");\n            var ConfirmBtn = $(\".confirm-btn\")[0];\n            //座位不能大于四\n            if((SeatMax>3) && (row.className == \"seat selectable\")){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('一次最多选四个座位！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.closeAll();\n                        }\n                    );\n                });\n            }\n            //确定\n            if((SeatMax<4) && (row.className == \"seat selectable\")){\n                row.className = \"seat selected\";\n                SeatMax++;\n                flag = 1;\n                Ticket.append(\"<span class=\\\"ticket\\\" data-index=\\\"\" + (i+1) + \"-\" + (j+1) + \"\\\">\" + (i+1) + \"排\" + (j+1) + \"座</span>\");\n                TicketPrice.text(\"￥\"+PriceTemp*SeatMax);\n            }\n            //取消\n            if((row.className == \"seat selected\") && (flag==0)){\n                TicketRemove = $(\"[data-index=\" + (i+1) + \"-\" + (j+1) + \"]\");\n                row.className = \"seat selectable\";\n                SeatMax--;\n                TicketRemove[0].remove();\n                TicketPrice.text(\"￥\"+PriceTemp*SeatMax);\n            }\n            if(SeatMax==0){\n                NoTicket.style.display = \"block\";\n                HasTicket.style.display = \"none\";\n                ConfirmBtn.className = \"confirm-btn disable\";\n            }\n            else{\n                NoTicket.style.display = \"none\";\n                HasTicket.style.display = \"block\";\n                ConfirmBtn.className = \"confirm-btn\";\n            }\n        }\n    \n        //初始化信息\n        function initInformation(){\n            var movieInfo = $(\".movie-info\");\n            var showInfo = $(\".show-info\");\n            $.ajax({\n                type:'post',\n                url: url + \"/schedule/findScheduleById\",\n                dataType:'json',\n                data: {\n                    schedule_id: schedule_id\n                },\n                success:function (obj) {\n                    TempLength = obj.data.orderList.length;\n                    for(var i=0;i<TempLength;i++){\n                        Seatrow[i] = obj.data.orderList[i].order_position.split(\"排\")[0];\n                        Seatcol[i] = obj.data.orderList[i].order_position.split(\"排\")[1].split(\"座\")[0];\n                    }\n                    console.log(obj);\n                    PriceTemp = obj.data.schedule_price;\n                    movieInfo.append(\n                        \"<div class=\\\"poster\\\">\" +\n                            \"<img src=\\\"\" + obj.data.schedule_movie.movie_picture + \"\\\">\" +\n                        \"</div>\" +\n                        \"<div class=\\\"content\\\">\" +\n                            \"<p class=\\\"name text-ellipsis\\\">\" + obj.data.schedule_movie.movie_cn_name + \"</p>\" +\n                            \"<div class=\\\"info-item\\\">\" +\n                                \"<span>类型：</span>\" +\n                                \"<span class=\\\"value\\\">\" + obj.data.schedule_movie.movie_type + \"</span>\" +\n                            \"</div>\" +\n                            \"<div class=\\\"info-item\\\">\" +\n                                \"<span>时长：</span>\" +\n                                \"<span class=\\\"value\\\">\" + obj.data.schedule_movie.movie_duration + \"</span>\" +\n                            \"</div>\" +\n                        \"</div>\"\n                    );\n                    showInfo.append(\n                        \"<div class=\\\"info-item\\\">\" +\n                            \"<span>影院：</span>\" +\n                            \"<span class=\\\"value\\\">\" + obj.data.schedule_hall.hall_cinema.cinema_name + \"</span>\" +\n                        \"</div>\" +\n                        \"<div class=\\\"info-item\\\">\" +\n                            \"<span>影厅：</span>\" +\n                            \"<span class=\\\"value\\\">\" +  obj.data.schedule_hall.hall_name + \"</span>\" +\n                        \"</div>\" +\n                        \"<div class=\\\"info-item\\\">\" +\n                            \"<span>版本：</span>\" +\n                            \"<span class=\\\"value\\\">\" +  obj.data.schedule_movie.movie_country + \"</span>\" +\n                        \"</div>\" +\n                        \"<div class=\\\"info-item\\\">\" +\n                            \"<span>场次：</span>\" +\n                            \"<span class=\\\"value\\\">\" + obj.data.schedule_startTime + \"</span>\" +\n                        \"</div>\" +\n                        \"<div class=\\\"info-item\\\">\" +\n                            \"<span>票价：</span>\" +\n                            \"<span class=\\\"value\\\">￥\" + obj.data.schedule_price + \"/张</span>\" +\n                        \"</div>\"\n                    );\n                    initSeat();\n                }\n            });\n        }\n    \n        //初始化座位表\n        function initSeat(){\n            var SeatRow = $(\".row-id-container\");\n            var seat = $(\".seats-wrapper\");\n            var row;\n            var HtmlRowHead = \"<div class=\\\"row\\\">\\n\";\n            var HtmlRowLast = \"</div>\";\n            var HtmlSeat;\n            var flag;\n            for(var i=0;i<12;i++)\n            {\n                SeatRow.append(\"<span class=\\\"row-id\\\">\" + (i + 1) + \"</span>\");\n                seat.append(HtmlRowHead);\n                row = $(\".seats-wrapper\").find(\".row\").last();\n                for(var j=0;j<12;j++)\n                {\n                    if(TempLength==0){\n                        HtmlSeat = \"<span class=\\\"seat selectable\\\" onclick=\\\"buySeat(\" + i + \",\" + j +\")\\\"></span>\";\n                    }\n                    else{\n                        flag = 0;\n                        for(var p=0;p<TempLength;p++){    \n                            if((Seatrow[p]==(i+1)) && (Seatcol[p]==(j+1))){\n                                flag = 1;\n                            }\n                        }\n                        if(flag==1){\n                            HtmlSeat = \"<span class=\\\"seat sold\\\" onclick=\\\"buySeat(\" + i + \",\" + j +\")\\\"></span>\";\n                        }\n                        else{\n                            HtmlSeat = \"<span class=\\\"seat selectable\\\" onclick=\\\"buySeat(\" + i + \",\" + j +\")\\\"></span>\";\n                        }\n                    }\n                    row.append(HtmlSeat);\n                }\n                seat.append(HtmlRowLast);\n            }\n        }\n\n        //确认选座\n        function confirm(){\n            var ticketContainer = $(\".ticket-container\").find(\".ticket\");\n            var price = $(\".price\").html();\n            price = price.replace(\"￥\",\"\");\n            var TicketSeat=\"\";\n            for(var i=0;i<ticketContainer.length;i++){\n                TicketSeat += ticketContainer[i].innerHTML;\n                if(i < (ticketContainer.length-1)){\n                    TicketSeat += \",\";\n                }\n            }\n            var json = {};\n            json.schedule_id = schedule_id;\n            json.TicketSeat = TicketSeat;\n            json.price = price;\n            localStorage.setItem(\"order\",JSON.stringify(json));\n            window.location.href=\"./pay.jsp\";\n           // window.location.href=\"./pay.jsp?schedule_id=\" + schedule_id + \"&TicketSeat=\" + TicketSeat + \"&price=\" + price;\n        }\n\n        //获取url参数\n        function getUrlParams(name) { // 不传name返回所有值，否则返回对应值\n            var url = window.location.search;\n            if (url.indexOf('?') == 1) { return false; }\n            url = url.substr(1);\n            url = url.split('&');\n            var name = name || '';\n            var nameres;\n            // 获取全部参数及其值\n            for(var i=0;i<url.length;i++) {\n                var info = url[i].split('=');\n                var obj = {};\n                obj[info[0]] = decodeURI(info[1]);\n                url[i] = obj;\n            }\n            // 如果传入一个参数名称，就匹配其值\n            if (name) {\n                for(var i=0;i<url.length;i++) {\n                    for (const key in url[i]) {\n                        if (key == name) {\n                            nameres = url[i][key];\n                        }\n                    }\n                }\n            } else {\n                nameres = url;\n            }\n            // 返回结果\n            return nameres;\n        }\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/buyTickets.jsp",
    "content": "﻿<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/buyTickets.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/movieDetail.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-选影院</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n  \n    <!-- 占位符 -->\n    <div style=\"margin-top: 80px;\"></div>\n\n    <!-- 巨幕 -->\n    <div class=\"banner2\">\n        <div class=\"wrapper clearfix\">\n            <div class=\"celeInfo-left\">\n                <div class=\"avatar-shadow\">\n                    <!-- 图片 -->\n                </div>\n            </div>\n            \n            <div class=\"celeInfo-right clearfix\">\n                <div class=\"movie-brief-container\">\n                    <!-- 上 -->\n                </div>\n                <div class=\"action-buyBtn\">\n                    <div class=\"action clearfix\" data-val=\"{movieid:42964}\">\n                        <a class=\"wish \" data-wish=\"false\" onclick=\"wantSee()\">\n                            <div>\n                                <i class=\"icon wish-icon\"></i>\n                                <span class=\"wish-msg\" data-act=\"wish-click\">想看</span>\n                            </div>\n                        </a>\n                        <a class=\"score-btn \" data-bid=\"b_rxxpcgwd\" onclick=\"giveScore()\">\n                            <div>\n                                <i class=\"icon score-btn-icon\"></i>\n                                <span class=\"score-btn-msg\" data-act=\"comment-open-click\">评分</span>\n                            </div>\n                        </a>\n                    </div>\n                </div>\n\n                <div class=\"movie-stats-container\">\n                    <div class=\"movie-index\">\n                        <p class=\"movie-index-title\">用户评分</p>\n                        <div class=\"movie-index-content score normal-score\">\n                            <span class=\"index-left info-num \">\n                                <!-- 评分 -->\n                            </span>\n                            <div class=\"index-right\">\n                                <div class=\"star-wrapper\">\n                                    <div id=\"MovieScore\"></div>\n                                </div>\n                                <span class=\"score-num\">\n                                    <!-- 评分数 -->\n                                </span>\n                            </div>\n                        </div>\n                    </div>   \n\n                    <div class=\"movie-index\">\n                        <p class=\"movie-index-title\">累计票房</p>\n                        <div class=\"movie-index-content box stonefont-num\">\n                            <!-- 票房数 -->\n                        </div>\n                    </div>\n                </div>\n\n            </div>\n        </div>\n    </div>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 50px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"main\">\n        <div class=\"main-inner main-buyticket\">\n            <!-- 标签 -->\n            <div class=\"tags-panel\">\n                <ul class=\"tags-lines\">\n                    <li class=\"tags-line\">\n                        <div class=\"tags-title\">日期:</div>\n                        <ul class=\"tags tags-date\">\n                            <!-- 日期 -->\n                        </ul>\n                    </li>\n                    <li class=\"tags-line tags-line-border\" data-type=\"brand\">\n                        <div class=\"tags-title\">品牌:</div>\n                        <ul class=\"tags tags-brand\">\n                            <!-- 品牌 -->\n                        </ul>\n                    </li>\n\n                    <li class=\"tags-line tags-line-border\" data-type=\"district\">\n                        <div class=\"tags-title\">行政区:</div>\n                        <ul class=\"tags tags-area\">\n                            <!-- 行政区 -->\n                        </ul>\n                    </li>\n\n                    <li class=\"tags-line tags-line-border\" data-type=\"hallType\">\n                        <div class=\"tags-title\">特殊厅:</div>\n                        <ul class=\"tags tags-hall\">\n                            <!-- 特殊厅 -->\n                        </ul>\n                    </li>\n            \n                </ul>\n            </div>\t\n            <!-- 列表 -->\n            <div class=\"cinemas-list\">\n                <h2 class=\"cinemas-list-header\">影院列表</h2>   \n            </div>\n            <!-- 分页 -->\n            <div class=\"cinema-pager\">\n                <ul class=\"list-pager\">\t\n                </ul>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var movie_id;\n        var date;\n        var brand;\n        var area;\n        var hall;\n        var page;\n        var ScoreHtml;\n        var CinemaLength;\n\n        window.onload = function(){\n            initHeader();\n            initParams(); //参数\n            initBanner(); //巨幕\n            initHtml(); //HTML\n            initTags(); //标签和分页\n        }\n\n        //初始化HTML\n        function initHtml(){\n            ScoreHtml = \n                \"<div style=\\\"text-align:center; margin:30px 0;\\\">\" +\n                    \"<div id=\\\"GiveScore\\\"></div>\" +\n                    \"<p style=\\\"color:#888;\\\">点击星星进行评分</p>\" +\n                \"</div>\"\n            ;\n        }\n\n        //初始化巨幕\n        function initBanner(){\n            movie_id = getUrlParams('movie_id');\n            var avatar = $(\".avatar-shadow\");\n            var movieBriefContainer = $(\".movie-brief-container\");\n            var infoNum = $(\".info-num\");\n            var scoreNum = $(\".score-num\");\n            var stonefontNum = $(\".stonefont-num\");\n            var actionBuyBtn = $(\".action-buyBtn\");\n            var StonefontTemp;\n\n            $.ajax({\n                type:'post',\n                url: url + \"/movie/findMovieById\",\n                dataType:'json',\n                data: {\n                    movie_id: movie_id\n                },\n                success:function (obj) {\n                    StonefontTemp = obj.data.movie_boxOffice;\n                    StonefontTemp += \"万\";\n                    avatar.append(\"<img class=\\\"avatar\\\" src=\\\"\" + obj.data.movie_picture + \"\\\" alt=\\\"\\\">\");\n                    movieBriefContainer.append(\n                    \"<h3 class=\\\"name\\\">\" + obj.data.movie_cn_name + \"</h3>\" +\n                    \"<div class=\\\"ename ellipsis\\\">\" + obj.data.movie_fg_name + \"</div>\" +\n                    \"<ul>\" +\n                        \"<li class=\\\"ellipsis\\\">\" + obj.data.movie_type + \"</li>\" +\n                        \"<li class=\\\"ellipsis\\\">\" + obj.data.movie_duration + \" / \" + obj.data.movie_country + \"</li>\" +\n                        \"<li class=\\\"ellipsis\\\">\" + obj.data.releaseDate + \"</li>\" +\n                    \"<ul>\");\n                    infoNum.append(\"<span class=\\\"stonefont\\\">\" + obj.data.movie_score + \"</span>\");\n                    scoreNum.append(\"<span class=\\\"stonefont\\\">\" + obj.data.movie_commentCount + \"</span>人评分\");\n                    stonefontNum.append(\"<span class=\\\"stonefont\\\">\" + StonefontTemp + \"</span>\");\n                    actionBuyBtn.append(\"<a class=\\\"btn buy\\\" href=\\\"./movieDetail.jsp?movie_id=\" + movie_id + \"\\\" data-act=\\\"more-detail-click\\\">查看更多电影详情</a>\");\n                    layui.use('rate', function(){\n                        var rate = layui.rate;\n                        rate.render({\n                            elem: '#MovieScore'\n                            ,value: (obj.data.movie_score / 2)\n                            ,half: true\n                            ,readonly: true\n                        })\n                    });\n                    initList(obj);\n                }\n            });\n        }\n        //评分\n        function giveScore(){\n            layui.use(['rate','layer'], function(){\n                var layer = layui.layer;\n                var rate = layui.rate;\n                layer.open({\n                    type: 1\n                    ,title: \"电影评分\"\n                    ,closeBtn: false\n                    ,area: '400px;'\n                    ,shade: 0.8\n                    ,offset: clientHeight/5\n                    ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                    ,btn: ['确认评分', '取消']\n                    ,yes: function(){\n                        layer.alert('感谢你的评价,祝你生活愉快！',{icon: 0,offset: clientHeight/5},\n                            function (){\n                                layer.closeAll();\n                                location.reload();\n                            }\n                        );\n                    }\n                    ,btnAlign: 'c'\n                    ,moveType: 0 //拖拽模式，0或者1\n                    ,content: ScoreHtml\n                    ,success: function(layero){\n                        rate.render({\n                            elem: '#GiveScore'\n                            ,value: 4.5\n                            ,half: true\n                            ,text: true\n                            ,setText: function(value){\n                                this.span.text(value*2+\"分\");\n                            }\n                        })\n                    }\n                });\n            });\n        }\n        //想看\n        function wantSee(){\n            layui.use(['rate','layer'], function(){\n                var layer = layui.layer;\n                var rate = layui.rate;\n                layer.alert('感谢你的支持！',{icon: 0,offset: clientHeight/5},\n                    function (){\n                        layer.closeAll();\n                        location.reload();\n                    }\n                );\n            });\n        }\n\n        //初始化标签和分页\n        function initTags(){\n            var Data = new Date();\n            var Month = Data.getMonth() + 1;\n            var Day = Data.getDate();\n            var tagsDate = $(\".tags-date\"),\n                tagsBrand = $(\".tags-brand\"),\n                tagsArea = $(\".tags-area\"),\n                tagsHall = $(\".tags-hall\");\n            var DateStr = [\"今天\",\"明天\",\"后天\",\"大后天\"],\n                BrandStr = [\"全部\",\"金逸影院\",\"大地影院\",\"中影国际影院\",\"万达影城\",\"CGV影城\",\"恒大影城\",\"五月花电影城\",\"博纳国际影城\",\"星美国际影城\",\"比高电影城\"],\n                AreaStr = [\"全部\",\"小榄\",\"石岐区\",\"五桂山区\",\"火炬开发区\",\"西区\",\"古镇\",\"南朗镇\",\"三乡镇\",\"东凤镇\",\"阜沙镇\",\"大涌镇\"],\n                HallStr = [\"全部\",\"普通厅\",\"IMAX厅\",\"CGS中国巨幕厅\",\"杜比全景声厅\",\"DTS:X临境音厅\",\"4K厅\",\"4D厅\"];\n            var DateActive = [],\n                BrandActive = [],\n                AreaActive = [],\n                HallActive = [];\n                PageActive = [];\n            var urlTemp = [\"&date=\"+date,\"&brand=\"+brand,\"&area=\"+area,\"&hall=\"+hall,\"&page=\"+page];\n            DateActive = inputTags(DateStr.length, DateActive, date);\n            BrandActive = inputTags(BrandStr.length, BrandActive, brand);\n            AreaActive = inputTags(AreaStr.length, AreaActive, area);\n            HallActive = inputTags(AreaStr.length, HallActive, hall);\n            for(var i=0;i<DateStr.length;i++){\n                urlTemp[0] = \"&date=\"+ i;\n                tagsDate.append(\n                    \"<li \" + DateActive[i] + \">\" +\n                        \"<a href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">\"+\n                            DateStr[i] + \" \" + Month + \"月\" + (Day+i) +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n            urlTemp = [\"&date=\"+date,\"&brand=\"+brand,\"&area=\"+area,\"&hall=\"+hall,\"&page=\"+page];\n            for(var i=0;i<BrandStr.length;i++){\n                urlTemp[1] = \"&brand=\"+ i;\n                tagsBrand.append(\n                    \"<li \" + BrandActive[i] + \">\" +\n                        \"<a href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">\"+\n                            BrandStr[i] +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n            urlTemp = [\"&date=\"+date,\"&brand=\"+brand,\"&area=\"+area,\"&hall=\"+hall,\"&page=\"+page];\n            for(var i=0;i<AreaStr.length;i++){\n                urlTemp[2] = \"&area=\"+ i;\n                tagsArea.append(\n                    \"<li \" + AreaActive[i] + \">\" +\n                        \"<a href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">\"+\n                            AreaStr[i] +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n            urlTemp = [\"&date=\"+date,\"&brand=\"+brand,\"&area=\"+area,\"&hall=\"+hall,\"&page=\"+page];\n            for(var i=0;i<HallStr.length;i++){\n                urlTemp[3] = \"&hall=\"+ i;\n                tagsHall.append(\n                    \"<li \" + HallActive[i] + \">\" +\n                        \"<a href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">\"+\n                            HallStr[i] +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n\n\n            // var listPager = $(\".list-pager\");\n            // var lengthtemp = 23;\n            // var PageNum = Math.floor(lengthtemp/10)+1;\n            // PageActive = inputTags(PageNum+1, PageActive, page);\n            // urlTemp = [\"&date=\"+date,\"&brand=\"+brand,\"&area=\"+area,\"&hall=\"+hall,\"&page=\"+page];\n            // if(page != 1){\n            //     urlTemp[4] = \"&page=\"+ (page-1);\n            //     listPager.append(\n            //         \"<li>\" +\n            //             \"<a onclick=\\\"changePage(\" + (page-1) + \")\\\" class=\\\"page\\\" href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">上一页</a>\" +\n            //         \"</li>\"\n            //     );\n            // }\n            // for(var i = 1;i<PageNum+1;i++){\n            //     urlTemp[4] = \"&page=\"+ i;\n            //     listPager.append(\n            //         \"<li>\" +\n            //             \"<a onclick=\\\"changePage(\" + i + \")\\\" \"+ PageActive[i] + \" href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">\" + i + \"</a>\" +\n            //         \"</li>\"\n            //     );\n            // }\n            // if(page != PageNum){\n            //     urlTemp[4] = \"&page=\" + (page-'-1');\n            //     listPager.append(\n            //         \"<li>\" +\n            //             \"<a onclick=\\\"changePage(\" + (page-'-1') + \")\\\" class=\\\"page\\\" href=\\\"?movie_id=\"+ movie_id + urlTemp[0] + urlTemp[1] + urlTemp[2] + urlTemp[3] + urlTemp[4] +\"\\\">下一页</a>\" +\n            //         \"</li>\"\n            //     );\n            // }\n        }\n        //导入活跃标签\n        function inputTags(length, Active, tags){\n            for(var i=0;i<length;i++){\n                if(tags==null&&i==0){\n                    Active.push(\"class=\\\"active\\\"\");\n                    break;\n                }\n                if(i==tags){\n                    Active.push(\"class=\\\"active\\\"\");\n                }\n                else\n                Active.push(\" \");\n            }\n            return Active;\n        }\n        //分页点击\n        function changePage(page){\n            console.log(page);\n        }\n\n        //初始化电影院列表\n        function initList(obj){\n            console.log(obj);\n            var cinemasList = $(\".cinemas-list\");\n            var ListLength;       \n            var TempPrice = [];\n            var MinPrice = [];\n            for(var i = 0;i< obj.cinemaList.length;i++){\n                var scheduleCount = 0;\n                for(var j = 0;j< obj.cinemaList[i].hallList.length;j++){\n                    if(obj.cinemaList[i].hallList[j].scheduleList.length ==0){\n                        scheduleCount++;\n                    }\n                }\n                if(scheduleCount == obj.cinemaList[i].hallList.length){\n                    obj.cinemaList.splice(i,1);\n                }\n            }\n            CinemaLength = obj.cinemaList.length;\n            for(var i=0;i<obj.cinemaList.length;i++){\n                TempPrice[i] = \"\";\n                for(var j=0;j<obj.cinemaList[i].hallList.length;j++){\n                    for(var p=0;p<obj.cinemaList[i].hallList[j].scheduleList.length;p++){\n                        TempPrice[i] += obj.cinemaList[i].hallList[j].scheduleList[p].schedule_price;\n                        TempPrice[i] += \",\";                  \n                    }\n                }\n                TempPrice[i] = TempPrice[i].substr(0, TempPrice[i].length - 1);  \n                MinPrice[i] = TempPrice[i].split(',').sort();\n            }\n            \n\n\n            if(obj.cinemaList.length<11){\n                ListLength = obj.cinemaList.length;\n            }\n            else{\n                ListLength = 10;\n            }\n            for(var i=0;i<ListLength;i++){\n                cinemasList.append(\n                    \"<div class=\\\"cinema-cell\\\">\" +\n                        \"<div class=\\\"cinema-info\\\">\" +\n                            \"<a class=\\\"cinema-name\\\">\" + obj.cinemaList[i].cinema_name + \"</a>\" +\n                            \"<p class=\\\"cinema-address\\\">地址：\" + obj.cinemaList[i].cinema_address + \"</p>\" +\n                        \"</div>\" +\n                        \"<div class=\\\"buy-btn\\\">\" +\n                            \"<a href=\\\"./selectSeat.jsp?cinema_id=\" + obj.cinemaList[i].cinema_id + \"&movie_id=\" + obj.data.movie_id + \"\\\">选座购票</a>\" +\n                        \"</div>\" +\n                        \"<div class=\\\"price\\\">\" +\n                            \"<span class=\\\"rmb red\\\">￥</span>\" +\n                            \"<span class=\\\"price-num red\\\"><span class=\\\"stonefont\\\">\"+ MinPrice[i].shift() +\"</span></span>\" +\n                            \"<span style=\\\"margin-left:5px;\\\">起</span>\" +\n                        \"</div>\" +\n                    \"</div>\"\n                );\n            }\n        }\n\n        //初始化url参数\n        function initParams(){\n            if(getUrlParams('date') == null){\n                date = \"0\";\n            }else{\n                date = getUrlParams('date');\n            }\n            if(getUrlParams('brand') == null){\n                brand = \"0\";\n            }else{\n                brand = getUrlParams('brand');\n            }\n            if(getUrlParams('area') == null){\n                area = \"0\";\n            }else{\n                area = getUrlParams('area');\n            }\n            if(getUrlParams('hall') == null){\n                hall = \"0\";\n            }else{\n                hall = getUrlParams('hall');\n            }\n            if(getUrlParams('page') == null){\n                page = \"1\";\n            }else{\n                page = getUrlParams('page');\n            }\n        }\n        //获取url参数\n        function getUrlParams(name) { // 不传name返回所有值，否则返回对应值\n            var url = window.location.search;\n            if (url.indexOf('?') == 1) { return false; }\n            url = url.substr(1);\n            url = url.split('&');\n            var name = name || '';\n            var nameres;\n            // 获取全部参数及其值\n            for(var i=0;i<url.length;i++) {\n                var info = url[i].split('=');\n                var obj = {};\n                obj[info[0]] = decodeURI(info[1]);\n                url[i] = obj;\n            }\n            // 如果传入一个参数名称，就匹配其值\n            if (name) {\n                for(var i=0;i<url.length;i++) {\n                    for (const key in url[i]) {\n                        if (key == name) {\n                            nameres = url[i][key];\n                        }\n                    }\n                }\n            } else {\n                nameres = url;\n            }\n            // 返回结果\n            return nameres;\n        }\n\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/center.jsp",
    "content": "<%@page import=\"com.entity.User\"%>\n<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<%\n\tUser user = (User)request.getSession().getAttribute(\"user\");\n\tif(user == null){\n\t\tresponse.sendRedirect(\"./login.jsp\");\n\t}\n%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/center.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-个人中心</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 110px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"container\">\n        <div class=\"contents\">\n            <div class=\"nav-next\">\n                <div class=\"nav-title\">\n                    <h3>个人中心</h3>\n                </div>\n                <a class=\"cardId\">我的订单</a>\n\t\t\t\t<a class=\"cardId\">基本信息</a>\n\t\t\t\t<a class=\"cardId\">修改密码</a>\n            </div>\n            <div class=\"nav-body\">\n                <!-- 我的订单 -->\n                <div class=\"one card\" style=\"display: block;\">\n                    <div>\n                        <div class=\"title\">我的订单</div>\n                        <hr/>\n                    </div>\n                </div>\n                <!-- 基本信息 账号、邮箱、角色、头像 -->\n                <div class=\"two card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">基本信息</div>\n                        <hr/>\n                    </div>\n                    <div class=\"avatar-container layui-upload\">\n                        <div class=\"layui-upload-list\">\n                            <img class=\"layui-upload-img\" id=\"demo1\">\n                            <p id=\"demoText\"></p>\n                        </div>\n                        <a href=\"javascript:;\" class=\"file\">选择文件\n                            <input type=\"file\" name=\"file\" id=\"file\">\n                        </a>\n                        <div class=\"tips\">支持JPG,JPEG,PNG格式，且文件需小于1000KB</div>\n                    </div>\n\n                    <div class=\"avatar-body\">\n                    </div>\n                </div>\n                <!-- 修改密码 -->\n                <div class=\"three card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">修改密码</div>\n                        <hr/>\n                    </div>\n                    <div class=\"avatar-body\">\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n    \n    \n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var user = localStorage.getItem(\"userJson\");\n        user = eval('(' + user + ')');\n        var file;\n\n        window.onload = function(){\n            initHeader();\n            initCard(); //初始化选项卡\n            initOrder(); //我的订单\n            initInformation(); //基本信息\n            initPassword(); //密码\n        }\n\n        //选项卡\n       function initCard(){\n            var aArr = $(\".nav-next\").find(\".cardId\");\n            var divArr = $(\".nav-body\").find(\".card\");\n            if(localStorage.getItem(\"usercardId\")==null){\n                localStorage.setItem(\"usercardId\",0);\n            }\n            for(var i=0; i<aArr.length; i++){\n                aArr[i].index = i;\n                aArr[i].onclick = function(){\n                    localStorage.setItem(\"usercardId\",this.index);\n                    for(var j=0;j<divArr.length;j++){\n                        divArr[j].style.display = \"none\";\n                        aArr[j].style.cssText = \"background-color: #f4f3f4; color: #333;\";\n                    }\n                    divArr[this.index].style.display = \"block\";\n                    aArr[this.index].style.cssText = \"background-color: #ed3931; color: #fff;\";\n                }\n            }\n            for(var p=0;p<aArr.length;p++){\n                divArr[p].style.display = \"none\";\n                aArr[p].style.cssText = \"background-color: #f4f3f4; color: #333;\";\n                if(localStorage.getItem(\"usercardId\")==p){\n                    divArr[p].style.display = \"block\";\n                    aArr[p].style.cssText = \"background-color: #ed3931; color: #fff;\";\n                }\n            }\n        }\n\n\n\n        //初始化“我的订单”\n        function initOrder(){\n            var order = $(\".one\");\n            var html;\n            $.ajax({\n                type:'post',\n                url: url + \"/order/findOrderByUserName\",\n                dataType:'json',\n                data: {\n                    user_name: user.user_name\n                },\n                success:function (obj) {\n                    // console.log(obj);\n                    for(var i=0;i<obj.data.length;i++){\n                      //  var order_time = obj.data[i].order_schedule.schedule_startTime.slice(0,10);\n                        var StateText;\n                        switch(obj.data[i].order_state){\n                            case 0:\n                                StateText = \"退票中\";\n                            break;\n                            case 1:\n                                StateText = \"已完成\";\n                            break;\n                            case 2:\n                                StateText = \"已退票\";\n                            break;\n                        }\n                        html = \n                        \"<div class=\\\"order-box\\\">\" +\n                            \"<div class=\\\"order-head\\\">\" +\n                                    \"<span class=\\\"order-date\\\">\" + obj.data[i].order_time + \"</span>\" +\n                                    \"<span class=\\\"order-id\\\">订单号：\" + obj.data[i].order_id + \"</span>\" +\n                                    \"<span class=\\\"order-delete\\\">*</span>\" +\n                                    \"</div>\" +\n                            \"<div class=\\\"order-body\\\">\" +\n                                \"<div class=\\\"poster\\\"><img src=\\\"\" + obj.data[i].order_schedule.schedule_movie.movie_picture + \"\\\"></div>\" +\n                                \"<div class=\\\"order-content\\\">\" +\n                                    \"<div class=\\\"movie-name\\\">\" + obj.data[i].order_schedule.schedule_movie.movie_cn_name + \"</div>\" +\n                                    \" <div class=\\\"cinema-name\\\">\" + obj.data[i].order_schedule.schedule_hall.hall_cinema.cinema_name + \"</div>\" +\n                                    \"<div class=\\\"hall-ticket\\\">\"  + obj.data[i].order_schedule.schedule_hall.hall_name + \" \" + obj.data[i].order_position + \"</div>\" +\n                                    \"<div class=\\\"show-time\\\">\" + obj.data[i].order_schedule.schedule_startTime + \"</div>\" +\n                                \"</div>\" +\n                                \"<div class=\\\"order-price\\\">￥\" + obj.data[i].order_schedule.schedule_price + \"</div>\" +\n                                \"<div class=\\\"order-status\\\">\" + StateText + \"</div>\" +\n                                \"<div class=\\\"actions\\\"><a onclick=\\\"backticket('\" + obj.data[i].order_id + \"','\" + obj.data[i].order_schedule.schedule_startTime  + \"','\" + StateText + \"')\\\" style=\\\"cursor: pointer;\\\">申请退票</a></div>\" +\n                            \"</div>\" +\n                        \"</div>\";\n                        order.append(html);\n                    }\n                }\n            });\n        }\n        //退票申请\n        function backticket(order_id,order_time,order_state){\n            var ShowTime = $(\".one\").find(\".show-time\");\n            var Year,Month,Day,Hour,Mintue,flag=0;\n            var myDate = new Date();\n            var OldTime, NowTime, OldDate, NowDate;\n            if(order_state==\"退票中\"){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('该订单正处于退票状态！',{icon: 0,offset: clientHeight/5});\n                });\n            }\n            else if(order_state==\"已退票\"){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('该订单已完成退票！',{icon: 0,offset: clientHeight/5});\n                });\n            }\n            else{\n                if(myDate.getHours()==23){\n                    flag=1;\n                }\n                OldTime = order_time;\n                NowTime = myDate.toLocaleDateString() + \" \" + parseInt(myDate.getHours()+1).toString()  + \":\" + myDate.getMinutes();\n                OldDate = new Date(OldTime.replace(/-/g,\"\\/\"));\n                NowDate = new Date(NowTime.replace(/-/g,\"\\/\"));\n                if(flag == 1){\n                    flag = 0;\n                    layui.use(['layer'], function(){\n                    var layer = layui.layer;\n                        layer.alert('23：00 - 00：00不给予退票操作！',{icon: 0,offset: clientHeight/5});\n                    });\n                }\n                else if(OldDate<NowDate){\n                    // window.alert(\"旧时间：\" + OldDate + \"\\n新时间：\" + NowDate + \"\\n退票时间为开场前1小时外，退票申请失败！\");\n                    layui.use(['layer'], function(){\n                    var layer = layui.layer;\n                        layer.alert('退票时间为开场前1小时外，退票申请失败！',{icon: 0,offset: clientHeight/5});\n                    });\n                }\n                else{\n                    // window.alert(\"旧时间：\" + OldDate + \"\\n新时间：\" + NowDate + \"\\n退票已申请\");\n                    layui.use(['layer'], function(){\n                    var layer = layui.layer;\n                        layer.alert('是否确认要申请退票！',{icon: 0,offset: clientHeight/5},\n                            function (){\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/order/applyForRefund\",\n                                    dataType:'json',\n                                    data: {\n                                        order_id: order_id\n                                    },\n                                    success:function (obj) {\n                                        if(obj.code == 0){\n                                            window.alert(\"退票已申请\");\n                                        }\n                                        else{\n                                            window.alert(\"退票申请失败！\");\n                                        }\n                                    }\n                                });\n                                layer.closeAll();\n                                location.reload();\n                            }\n                        );\n                    });\n                }\n            }      \n        }\n    \n        //初始化基本信息\n        function initInformation(){\n            var avatarBody = $(\".two\").find(\".avatar-body\");\n            var roletext;\n            if(user.user_role==1){\n                roletext = \"管理员\";\n            }\n            else{\n                roletext = \"会员\";\n            }\n\n            avatarBody.append(\n                \"<div class=\\\"userexinfo-form-section\\\">\" +\n                    \"<p>账号：</p>\" +\n                    \"<span>\" +\n                        \"<input type=\\\"text\\\" name=\\\"userName\\\" id=\\\"userName\\\" value=\\\"\" + user.user_name + \"\\\" disabled=\\\"false\\\">\" +\n                    \"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"userexinfo-form-section\\\">\" +\n                    \"<p>身份：</p>\" +\n                    \"<span>\" +\n                        \"<input type=\\\"text\\\" name=\\\"role\\\" id=\\\"role\\\" value=\\\"\" + roletext + \"\\\" disabled=\\\"false\\\">\" +\n                    \"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"userexinfo-form-section\\\">\" +\n                    \"<p>邮箱：</p>\" +\n                    \"<span>\" +\n                        \"<input type=\\\"text\\\" name=\\\"email\\\" id=\\\"email\\\" value=\\\"\" + user.user_email + \"\\\">\" +\n                    \"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"userexinfo-btn-section\\\">\" +\n                    \"<input type=\\\"button\\\" onclick=\\\"saveBtn()\\\" class=\\\"form-save-btn\\\" value=\\\"保存\\\">\" +\n                \"</div>\"\n            );\n            var HeadImg = \"\";\n            if(user.user_headImg == null || typeof user.user_headImg == \"undefined\"){\n                HeadImg = \"../upload/head/demo.jpg\";\n            }else{\n                HeadImg = user.user_headImg;\n            }\n            $('#demo1').attr('src', HeadImg);\n            \n            layui.use(['layer', 'table'], function(){\n                var layer = layui.layer;\n                var table = layui.table\n\n                //图片上传\n                layui.use('upload', function(){\n                    var $ = layui.jquery\n                    ,upload = layui.upload;         \n                    //普通图片上传\n                    var uploadInst = upload.render({\n                        elem: '#file'\n                        ,auto: false\n                        , choose: function (obj) {\n                            //预读本地文件\n                            obj.preview(function (index, file, result) {\n                                $('#demo1').attr('src', result); //图片链接（base64）\n                            })\n                            file = $('#file')[0].files[0];\n                        }\n                    });\n                });\n            });\n        }\n        //保存信息修改\n        function saveBtn(){\n            var formData = new FormData();\n            var user_name = $('#userName').val(),\n                user_role = $('#role').val(),\n                user_email = $('#email').val();\n            console.log(file);\n            console.log(user_name+ \",\" + user_role + \",\" + user_email);\n            if(user_role == \"会员\"){\n                user_role = 0;\n            }else{\n                user_role = 1;\n            }\n            if(user_email == \"\"){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('邮箱信息不能为空，修改失败！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.close(layer.index);\n                        }\n                    );\n                });\n            }\n            else{\n                formData.append(\"user_id\",user.user_id);\n                formData.append(\"user_name\",user_name);\n                formData.append(\"user_role\",user_role);\n                formData.append(\"user_email\",user_email);\n                formData.append(\"file\",file);\n                $.ajax({\n                    type:'post',\n                    url: url + \"/user/uploadHeadImg\",\n                   // dataType:'json',\n                    data: formData,\n                    processData: false,\n                    contentType: false,\n                    success:function (result) {\n                        var obj = eval('(' + result + ')');\n                        if(obj.code == 0){\n                            layer.alert('修改成功！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    localStorage.removeItem(\"userJson\");\n                                    layer.closeAll();\n                                    localStorage.setItem(\"userJson\",JSON.stringify(obj.data));\n                                    window.location.reload();\n                                }\n                            );\n                        }else{\n                            layer.alert('修改失败！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.closeAll();\n                                }\n                            );\n                        }\n                    }\n                });\n            }\n        }\n    \n        //初始化密码\n        function initPassword(){\n            var avatarBody = $(\".three\").find(\".avatar-body\");\n\n            avatarBody.append(\n                \"<div class=\\\"userexinfo-form-section\\\">\" +\n                    \"<p>旧密码：</p>\" +\n                    \"<span>\" +\n                        \"<input type=\\\"password\\\" name=\\\"oldPassword\\\" id=\\\"oldPassword\\\" value=\\\"\\\">\" +\n                    \"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"userexinfo-form-section\\\">\" +\n                    \"<p>新密码：</p>\" +\n                    \"<span>\" +\n                        \"<input type=\\\"password\\\" name=\\\"newPassword\\\" id=\\\"newPassword\\\" value=\\\"\\\">\" +\n                    \"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"userexinfo-form-section\\\">\" +\n                    \"<p>确认密码：</p>\" +\n                    \"<span>\" +\n                        \"<input type=\\\"password\\\" name=\\\"repeatPassword\\\" id=\\\"repeatPassword\\\" value=\\\"\\\">\" +\n                    \"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"userexinfo-btn-section\\\">\" +\n                    \"<input type=\\\"submit\\\" onclick=\\\"savePasswordBtn()\\\" class=\\\"password-save-btn\\\" value=\\\"保存\\\">\" +\n                \"</div>\"\n            );\n        }\n        //保存密码修改\n        function savePasswordBtn(){\n            var user_old_password = $('#oldPassword').val(),\n                user_new_password = $('#newPassword').val(),\n                user_repeat_password = $('#repeatPassword').val();\n            var user_id = user.user_id;\n            console.log(user_old_password+ \",\" + user_new_password + \",\" + user_repeat_password);\n            if(user_old_password == \"\" || user_new_password == \"\" || user_repeat_password == \"\"){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('密码修改信息不能为空，修改失败！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.close(layer.index);\n                        }\n                    );\n                });\n            }\n            else if(user_old_password != user.user_pwd){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('旧密码输入错误！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.close(layer.index);\n                        }\n                    );\n                });\n            }\n            else if(user_new_password != user_repeat_password){\n                layui.use(['layer'], function(){\n                var layer = layui.layer;\n                    layer.alert('新密码和确认密码不匹配！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.close(layer.index);\n                        }\n                    );\n                });\n            }\n            else{\n                $.ajax({\n                    type:'post',\n                    url: url + \"/user/modifyUserPwd\",\n                    dataType:'json',\n                    data: {\n                        oldPwd: user_old_password,\n                        newPwd: user_new_password,\n                        user_id: user_id,\n                    },\n                    success:function (obj) {\n                        if(obj == \"success\"){\n                            layer.alert('修改成功，请重新登陆！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.closeAll();\n                                    localStorage.removeItem(\"userJson\");\n                                    window.location.reload();\n                                }\n                            );\n                        }else{\n                            layer.alert('修改失败！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.closeAll();\n                                }\n                            );\n                        }\n                    }\n                });\n            }\n        }\n\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/footer.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%> \n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n</head>\n<body>\n    <div class=\"footer\">\n        <div>\n            <p>鹰眼电影网上购票系统</p>\n            <p>\n               友情链接:\n                <a href=\"https://maoyan.com/\" target=\"_blank\" style=\"margin-right:30px;\">猫眼电影</a>\n                <span onclick=\"footerBtn()\" style=\"height: 20px; cursor: pointer; border-left:0px\">\n                    美女客服：\n                    <img src=\"../static/images/客服.jpg\" style=\"width: 20px;\">\n                </span>\n            </p>\n            <p>\n                组长：翁修杰\n                小组成员：梁颂伟、魏泽伟、黄泽伟、李鹏飞\n                <br>\n                后台：翁修杰\n                前端：梁颂伟\n                前端协助：魏泽伟、黄泽伟、李鹏飞\n            </p>\n            <p>©2019 版权归小组成员所有</p>\n        </div>\n    </div>\n</body>\n<script>\n//美女客服\n        function footerBtn(){\n            layui.use(['layer'], function(){\n                var layer = layui.layer;\n                layer.open({\n                    type: 1\n                    ,title: \"美女客服\" //不显示标题栏\n                    ,closeBtn: false\n                    ,area: '400px;'\n                    ,shade: 0.8\n                    ,offset: clientHeight/20\n                    ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                    ,btn: ['确认', '取消']\n                    ,yes: function(){\n                        layer.close(layer.index);\n                    }\n                    ,btnAlign: 'c'\n                    ,moveType: 0 //拖拽模式，0或者1\n                    ,content: \n                        \"<div style=\\\"text-align: center; margin: 20px 0 10px 0;\\\">\" +\n                            \"<img src=\\\"../static/images/美女客服.jpg\\\" style=\\\"width:320px;\\\">\" +\n                        \"</div>\"\n                });\n            });\n        }\n</script>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/header.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%> \n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影</title>\n</head>\n<body>\n \t<!-- 导航栏 -->\n     <div class=\"header navbar navbar-fixed-top\">\n        <div class=\"header-top\">\n            <div class=\"header-inner\">\n                <h1>\n                    <a href=\"javascript:void(0)\" class=\"logo\"></a>\n                </h1>\n                <div class=\"nav\">\n                    <ul>\n                        <li><a href=\"./mainPage.jsp\">首页</a></li>\n                        <li class=\"active\"><a href=\"./movieList.jsp\">电影</a></li>\n                        <li><a href=\"javascript:void(0)\">影院</a></li>\n                        <li><a href=\"javascript:void(0)\">榜单</a></li>\n                    </ul>\n                </div>\n                <div class=\"app-download\">\n                </div>\n                <div class=\"user-info\">\n                <div class=\"user-avatar J-login\">\n                    <ul class=\"layui-nav\" style=\"background-color: #fff;\">\n                        <li class=\"layui-nav-item header-li\" style=\"width:40px;\" lay-unselect=\"\" style=\"width: 40px;\">\n                        </li>\n                    </ul>\n                </div>\n                </div>\n                <form action=\"\">\n                    <input name=\"searchMovie\" class=\"search\" type=\"search\" maxlength=\"32\" placeholder=\"找影视剧、影人、影院\" autocomplete=\"off\">\n                <input class=\"submit\" type=\"submit\" value=\"\">\n                </form>\n            </div>\n        </div>\n    </div>\n\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        window.onload = function(){\n            initHeader();\n        }\n\n        \n    </script>\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/login.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link href=\"../static/css/login.css\" rel=\"stylesheet\">\n\n    <script></script>\n    <title>鹰眼电影-登录注册</title>\n</head>\n<body>\n\n    <!-- ------------------------------------------------------------------- -->\n    <div class=\"screen\">\n        <img class=\"big_logo\"><br/>\n        <label class=\"title\">鹰 眼 电 影</label><br/>\n        <label class=\"ineer_one\">回首向来风雨茶香里</label><br/>\n        <label class=\"ineer_two\">眸中一点可是思念谁</label>\n    </div>\n    <!-- 登录页 -->\n    <div class=\"content\" style=\"float: left;\">\n        <ul class=\"tab\">\n            <li class=\"login\">登录</li>\n            <li class=\"register\">注册</li>\n        </ul>\n        <div class=\"page\">\n            <!-- 登录界面 -->\n            <div class=\"childpage\" style=\"display: block\">\n                <div>\n                    <label class=\"login_title\">用户登录</label><br/>\n                </div>\n                <div class=\"login_page\">\n                    <div>\n                        <label>帐号</label><br/>\n                        <input id=\"UserName\" type=\"text\"/>\n                    </div>\n                    <div>\n                        <label>密码</label><br/>\n                        <input id=\"PassWord\" type=\"password\"/>\n                    </div>\n                </div>\n                <div class=\"lo_error\">\n                    <label class=\"login_error\"></label>\n                </div>\n                <div>\n                    <input type=\"button\" value=\"登录\" class=\"btn btn-success login_btn\" onclick=\"loginbtn()\"/>\n                </div>\n                <div>\n                    <label class=\"login_version\">@版权所有</label>\n                </div>\n            </div>\n            <!-- 注册界面 -->\n            <div class=\"childpage\" style=\"display: none\">\n                <div>\n                    <label class=\"register_title\">用户注册</label><br/>\n                </div>\n                <div class=\"register_page\">\n                    <div>\n                        <label>帐号</label><br/>\n                        <input id=\"UserName\" type=\"text\"/>\n                    </div>\n                    <div>\n                        <label>密码</label><br/>\n                        <input id=\"PassWord\" type=\"password\"/>\n                    </div>\n                    <div>\n                        <label>邮箱</label><br/>\n                        <input id=\"Email\" type=\"text\"/>\n                    </div>\n                    <div>\n                        <label>验证码</label><br/>\n                        <input id=\"Test\" type=\"text\"/>\n                        <input id=\"TestNum\" type=\"button\"/>\n                    </div>\n                </div>\n                <div class=\"re_error\">\n                    <label class=\"register_error\"></label>\n                </div>\n                <div>\n                    <input type=\"button\" value=\"注册\" class=\"btn btn-warning register_btn\" onclick=\"registerbtn()\"/>\n                </div>\n                <div>\n                    <label class=\"register_version\">@版权所有</label>\n                </div>\n            </div>\n        </div>\n        \n    </div>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        //初始化\n        window.onload = function(){ \n            initWindow(); //初始化登录框位置\n            initLogin(); //初始化登录界面\n    　　}; \n\n        //初始化登录框位置（垂直居中、水平4/7）\n        function initWindow(){\n            var middle = 3;\n            var colorNum = 200;\n            var clientHeight = document.documentElement.clientHeight;\n            var clientWidth = document.documentElement.clientWidth;\n            var content = document.getElementsByClassName('content')[0];\n            var screen = document.getElementsByClassName('screen')[0];\n            var title = document.getElementsByClassName('title')[0];\n            var bodys = document.getElementsByTagName('body')[0];\n            bodys.style.cssText = \"background-size: \" + clientWidth + \"px auto;\";\n            content.style.cssText = \"margin:\" + (clientHeight - content.clientHeight)/2 +\"px \" + \n            clientWidth*4/7 + \"px \" +\n            (clientHeight - content.clientHeight)/2 + \"px;\";\n            screen.style.cssText = \"margin:\" + (content.clientHeight - screen.clientHeight)/2 +\"px \" + \n            (clientWidth*4/7 - screen.clientWidth)/2 + \"px \" +\n            (content.clientHeight - screen.clientHeight)/2 + \"px;\";\n            setInterval(function(){\n                colorNum += middle;\n                if(colorNum>185){\n                    middle = -3;\n                }else if(colorNum<80){\n                    middle = 3;\n                }\n                title.style.cssText = \"color:rgb(255,\" + colorNum + \", 0)\";\n            },30);\n        }\n\n        //初始化登录界面\n        function initLogin(){\n            var textNum = document.getElementById('TestNum');\n            var liArr = document.getElementsByTagName('li');\n    \t\tvar divArr = document.getElementsByClassName(\"page\")[0].getElementsByClassName(\"childpage\");\n            textNum.onclick = function(){\n                textNum.value = TestNum();\n            }\n    \t\tfor(var i=0;i<liArr.length;i++){\n    \t\t\tliArr[i].index = i;\n    \t\t\tliArr[i].onclick = function(){\n                    textNum.value = TestNum();\n    \t\t\t\tfor(var j=0;j<divArr.length;j++){\n                        liArr[j].style.cssText = \"background-color:rgba(255, 255, 255, 0.2);\";\n    \t\t\t\t\tdivArr[j].style.display = \"none\";\n    \t\t\t\t}\n                    liArr[this.index].style.cssText = \"background-color:rgba(255, 255, 255, 0);\";\n    \t\t\t\tdivArr[this.index].style.display = \"block\";\n    \t\t\t}\n    \t\t}\n        }\n        \n        //更新验证码\n        function TestNum(){\n            var testNum = \"\";\n            var selectChar = new Array(0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f','g','h','i','j','k','l',\n                'm','n','o','p','q','r','s','t','u','v','w','x','y','z');\n            for(var i=0;i<4;i++){\n                var charIndex = Math.floor(Math.random()*36);\n                testNum +=selectChar[charIndex];\n            }\n            return testNum;\n        }\n\n         //登录账号和密码信息验证\n         function loginbtn(){\n            var user_name = $(\".login_page\").find(\"#UserName\").val();\n            var user_pwd = $(\".login_page\").find(\"#PassWord\").val();\n            var login_error = $(\".login_error\");\n            if((user_name == \"\") || (user_pwd == \"\")){\n                login_error.text(\"账号和密码不能为空\");\n            }\n            else{\n                login_error.text(\"\");\n                $.ajax({\n                    type: \"post\",\n                    url: url + \"/user/login\",\n                    data: {\n                        user_name: user_name,\n                        user_pwd: user_pwd\n                    },\n                    dataType: \"json\",\n                    success: function(obj){\n                        if(obj.msg == \"fail\"){\n                           // sessionStorage.removeItem('userJson');\n                            login_error.text('账号或密码错误!');\n                        }\n                        else{\n                            localStorage.setItem(\"userJson\",JSON.stringify(obj.data));\n                          // sessionStorage.set\n                            window.location.href=\"./mainPage.jsp\";\n                        }\n                    },\n                    error:function(){\n                        alert(\"network error!\");\n                    }\n                });\n            }\n        }\n\n        //注册账号和密码逻信息验证\n        function registerbtn(){\n            var textNum = document.getElementById('TestNum'); \n            var user_name = $(\".register_page\").find(\"#UserName\").val();\n            var user_pwd = $(\".register_page\").find(\"#PassWord\").val();\n            var user_email = $(\".register_page\").find(\"#Email\").val();\n            var register_error = $(\".register_error\");\n            var test = $(\"#Test\").val();\n            var testbtn = $(\"#TestNum\").val();\n            if((user_name == \"\") || (user_pwd == \"\") || (user_email == \"\")){\n                register_error.text(\"账号和密码和邮箱不能为空\");\n                textNum.value = TestNum();\n            }\n            else if((test == \"\") || test!=testbtn){\n                register_error.text(\"验证码错误\");\n                textNum.value = TestNum();\n            }\n            else{\n                register_error.text(\"\");\n                $.ajax({\n                    type: \"post\",\n                    url: url + \"/user/register\",\n                    data: {\n                        user_name: user_name,\n                        user_pwd: user_pwd,\n                        user_email: user_email\n                    },\n                    dataType: \"json\",\n                    success: function(data){\n                        console.log(data);\n                        if(data == \"success\"){\n                            window.alert(\"注册成功！\");\n                            window.location.href=\"./login.jsp\";\n                        }else{\n                            register_error.text('该账号已被注册!');\n                        }\n                    }\n                });\n            }\n        }\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/mainPage.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main2.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-首页</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 100px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"main\">\n        <div class=\"main-inner main-page\">\n            <div class=\"layui-carousel\" id=\"test3\" lay-filter=\"test4\">\n                <div carousel-item=\"\">\n                    <div>\n                        <img src=\"../static/images/pic1.jpg\">\n                    </div>\n                    <div>\n                        <img src=\"../static/images/pic2.jpg\">\n                    </div>\n                    <div>\n                        <img src=\"../static/images/pic3.jpg\">\n                    </div>\n                    <div>\n                        <img src=\"../static/images/pic4.jpg\">\n                    </div>\n                    <div>\n                        <img src=\"../static/images/pic5.jpg\">\n                    </div>\n                </div>\n            </div> \n            <div class=\"aside\">\n                <!-- 1 -->\n                <div class=\"ranking-box-wrapper\">\n                    <div class=\"panel sidepanel\">\n                        <div class=\"panel-header\">\n                            <span class=\"panel-title\">\n                                <span class=\"textcolor_red\">总体票房</span>\n                            </span>\n                        </div>\n                        <div class=\"panel-content\">\n                            <ul class=\"ranking-wrapper ranking-box boxOffice\">\n                            </ul>\n                        </div>\n                    </div>\n                </div>\n                <!-- 2 -->\n                <div class=\"box-total-wrapper clearfix\" style=\"height: 80px\">\n                    \n                </div>\n                <!-- 3 -->\n                <div class=\"most-expect-wrapper\">\n                        <div class=\"panel\">\n                          <div class=\"panel-header\">\n                            <span class=\"panel-more\">\n                              <a href=\"#\" class=\"textcolor_orange\" data-act=\"all-mostExpect-click\">\n                                <span>查看完整榜单</span>\n                              </a>\n                              <span class=\"panel-arrow panel-arrow-orange\"></span>\n                            </span>\n                            <span class=\"panel-title\">\n                              <span class=\"textcolor_orange\">最受期待</span>\n                            </span>\n                          </div>\n                          <div class=\"panel-content\">\n                                  <ul class=\"ranking-wrapper ranking-mostExpect\">\n                                  <li class=\"ranking-item ranking-top ranking-index-1\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1229534}\">\n                              <div class=\"ranking-top-left\">\n                                <i class=\"ranking-top-icon\"></i>\n                                  <img class=\"ranking-img  default-img\" src=\"https://p0.meituan.net/movie/bb9f75599bfbb2c4cf77ad9abae1b95c1376927.jpg@140w_194h_1e_1c\">\n                              </div>\n                              <div class=\"ranking-top-right\">\n                                <div class=\"ranking-top-right-main\">\n                                  <span class=\"ranking-top-moive-name\">银河补习班</span>\n                      \n                                    <p class=\"ranking-release-time\">上映时间：2019-07-18</p>\n                      \n                                    <p class=\"ranking-top-wish\">\n                                        <span class=\"stonefont\">634541</span>人想看\n                                    </p>\n                                </div>\n                              </div>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-2\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:346210}\">\n                                <i class=\"ranking-index\">2</i>\n                                <span class=\"img-link\"><img class=\"ranking-img default-img\" src=\"https://p1.meituan.net/movie/268a41fb0de323c1edff30d308e48537234842.jpg@170w_118h_1e_1c\"></span>\n                                <div class=\"name-link ranking-movie-name\">八佰</div>\n                      \n                                <span class=\"ranking-num-info\"><span class=\"stonefont\">517365</span>人想看</span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-3\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1227611}\">\n                                <i class=\"ranking-index\">3</i>\n                                <span class=\"img-link\"><img class=\"ranking-img default-img\" src=\"https://p0.meituan.net/movie/7aebe625a4a335ed1bf346374506c77a1018128.jpg@170w_118h_1e_1c\"></span>\n                                <div class=\"name-link ranking-movie-name\">小小的愿望</div>\n                      \n                                <span class=\"ranking-num-info\"><span class=\"stonefont\">392336</span>人想看</span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-4\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1215605}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">4</i>\n                                  <span class=\"ranking-movie-name\">速度与激情：特别行动</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">315230</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-5\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1197417}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">5</i>\n                                  <span class=\"ranking-movie-name\">使徒行者2：谍影行动</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">306130</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-6\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1217023}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">6</i>\n                                  <span class=\"ranking-movie-name\">唐人街探案3</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">137888</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-7\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1203134}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">7</i>\n                                  <span class=\"ranking-movie-name\">摸金校尉之九幽将军</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">112327</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-8\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:342903}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">8</i>\n                                  <span class=\"ranking-movie-name\">上海堡垒</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">90324</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-9\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1250700}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">9</i>\n                                  <span class=\"ranking-movie-name\">攀登者</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">63547</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                                  <li class=\"ranking-item ranking-index-10\">\n                            <a target=\"_blank\" data-act=\"mostExpect-movie-click\" data-val=\"{movieid:1207254}\">\n                                <span class=\"normal-link\">\n                                  <i class=\"ranking-index\">10</i>\n                                  <span class=\"ranking-movie-name\">鼠胆英雄</span>\n                      \n                                  <span class=\"ranking-num-info\">\n                                      <span class=\"stonefont\">35739</span>人想看\n                                    </span>\n                                </span>\n                            </a>\n                          </li>\n                      \n                      </ul>\n                      \n                      \n                          </div>\n                        </div>\n                </div>\n            </div>\n            <div class=\"movie-grid\">\n\n                <div class=\"panel-header\">\n                    <span class=\"panel-more\">\n                        <a href=\"./movieList.jsp\" class=\"textcolor_red\" data-act=\"all-playingMovie-click\">\n                            <span>全部</span>\n                        </a>\n                        <span class=\"panel-arrow panel-arrow-red\"></span>\n                    </span>\n                    <span class=\"panel-title hot-title\">\n                    </span>\n                </div>\n                <div class=\"panel-content\">\n                    <ul class=\"movie-list movie-hot\">\n                    </ul>\n                </div>\n                <div class=\"panel\">\n                    <span class=\"panel-more\">\n                        <a href=\"./movieList.jsp\" class=\"textcolor_red\" data-act=\"all-upcomingMovie-click\">\n                            <span>全部</span>\n                        </a>\n                        <span class=\"panel-arrow panel-arrow-blue\"></span>\n                    </span>\n                    <span class=\"panel-title on-title\">\n                    </span>\n                </div>\n                <div class=\"panel-content\">\n                    <ul class=\"movie-list movie-on\">\n                    </ul>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n    \n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n\n        window.onload = function(){\n            initHostMovie(); //初始化正在热映和即将上映电影\n            //initBoxOffice(); //初始化总体票房\n            initHeader();\n        }\n\n        //图片轮播\n        layui.use(['carousel', 'form'], function(){\n            var carousel = layui.carousel, form = layui.form;\n            carousel.render({\n                elem: '#test3'\n                ,width: '100%'\n                ,height: '368px'\n                ,interval: 5000\n            });\n        });\n        \n        //初始化正在热映和即将上映电影\n        function initHostMovie(){\n            var MoiveLiHot = $(\".movie-hot\");\n            var MoiveLiOn = $(\".movie-on\");\n            var htmlHot,htmlOn;\n            var ListLength;\n            var notice, sale;\n            var HotNum = $(\".hot-title\");\n            var OnNum = $(\".on-title\");\n            var TempName;\n\n            $.ajax({\n                type:'post',\n                url: url + \"/movie/findAllMovies\",\n                dataType:'json',\n                data: {},\n                success:function (obj) {\n                    console.log(obj);\n                    HotNum.append(\"<span class=\\\"textcolor_red\\\">正在热映（\" + obj.data.length + \"部）</span>\");\n                    if(obj.data.length<8){\n                        ListLength = obj.data.length;\n                    }\n                    else{\n                        ListLength = 8;\n                    }\n                    for(var i=0;i<ListLength;i++){\n                        htmlHot =\n                        \"<li>\" +\n                            \"<div class=\\\"movie-item\\\">\" +\n                                \"<a href=\\\"javascript:void(0)\\\" target=\\\"_blank\\\" data-act=\\\"playingMovie-click\\\" data-val=\\\"\" + obj.data[i].movie_id + \"\\\">\" +\n                                    \"<div class=\\\"movie-poster\\\" style=\\\"cursor:default;\\\">\" +\n                                        \"<img id=\\\"moive_picture\\\" src=\\\"\" + obj.data[i].movie_picture + \"\\\">\" +\n                                        \"<div class=\\\"movie-overlay movie-overlay-bg\\\">\" +\n                                            \"<div class=\\\"movie-info\\\">\" +\n                                                \"<div class=\\\"movie-score\\\"><i id=\\\"moive_score\\\" class=\\\"integer\\\">\" + obj.data[i].movie_score + \"</i></div>\" +\n                                                \"<div class=\\\"movie-title movie-title-padding\\\" title=\\\"\" + obj.data[i].movie_cn_name + \"\\\">\" + obj.data[i].movie_cn_name + \"</div>\" +\n                                            \"</div>\" +\n                                        \"</div>\" +\n                                    \"</div>\" +\n                                \"</a>\" +\n                                \"<div class=\\\"movie-detail movie-detail-strong movie-sale\\\">\" +\n                                    \"<a href=\\\"./buyTickets.jsp?movie_id=\" + obj.data[i].movie_id + \"\\\" class=\\\"active\\\" target=\\\"_blank\\\" data-act=\\\"salePlayingMovie-click\\\" data-val=\\\"{movieid:42964}\\\">购 票</a>\" +\n                                \"</div>\" +\n                            \"</div>\" +\n                        \"</li>\";\n                        MoiveLiHot.append(htmlHot);\n                    }\n\n\n                    OnNum.append(\"<span class=\\\"textcolor_blue\\\">即将上映（\" + obj.data1.length + \"部）</span>\");\n                    if(obj.data1.length<8){\n                        ListLength = obj.data1.length;\n                    }\n                    else{\n                        ListLength = 8;\n                    }\n                    for(var i=0;i<ListLength;i++){\n                        var random = Math.floor(Math.random(1,10)*50000);\n                        htmlOn =\n                        \"<li>\" +\n                            \"<div class=\\\"movie-item\\\">\" +\n                                \"<a href=\\\"javascript:void(0)\\\" target=\\\"_blank\\\" data-act=\\\"playingMovie-click\\\" data-val=\\\"\" + obj.data1[i].movie_id + \"\\\">\" +\n                                    \"<div class=\\\"movie-poster\\\" style=\\\"cursor:default;\\\">\" +\n                                        \"<img id=\\\"moive_picture\\\" src=\\\"\" + obj.data1[i].movie_picture  + \"\\\">\" +\n                                        \"<div class=\\\"movie-overlay movie-overlay-bg\\\">\" +\n                                            \"<div class=\\\"movie-info\\\">\" +\n                                                \"<div class=\\\"movie-score\\\"><i id=\\\"moive_score\\\" class=\\\"integer\\\">\" + obj.data1[i].movie_score + \"</i></div>\" +\n                                                \"<div class=\\\"movie-title movie-title-padding\\\" title=\\\"\" + obj.data1[i].movie_cn_name + \"\\\">\" + obj.data1[i].movie_cn_name + \"</div>\" +\n                                            \"</div>\" +\n                                        \"</div>\" +\n                                    \"</div>\" +\n                                \"</a>\" +\n                                \"<div class=\\\"movie-detail movie-wish\\\"><span class=\\\"stonefont\\\">\" + random + \"</span>人想看</div>\" +\n                                \"<div class=\\\"movie-detail movie-detail-strong movie-presale\\\">\" +\n                                    \"<a id=\\\"movie-notice\\\" class=\\\"movie-presale-sep movie-notice\\\">预告片</a>\" +\n                                    \"<a id=\\\"movie-sale\\\" class=\\\"movie-presale-sep movie-sale\\\">预 售</a>\" +\n                                \"</div>\" +\n                            \"</div>\" +\n                        \"</li>\";\n                        MoiveLiOn.append(htmlOn);\n                    }\n                    notice = $(\".movie-on\").find(\".movie-notice\");\n                    sale = $(\".movie-on\").find(\".movie-sale\");\n                    for(var i=0;i<ListLength;i++){\n                        notice[i].index = i;\n                        notice[i].onclick = function(){ \n                            layer.alert('‘' + obj.data1[this.index].movie_cn_name + '’电影暂未有预告片！',{icon: 0,offset: clientHeight/7});\n                        }\n                        sale[i].index = i;\n                        sale[i].onclick = function(){\n                            layer.alert('预售‘' + obj.data1[this.index].movie_cn_name + '’电影成功！',{icon: 0,offset: clientHeight/7});\n                        }\n                    }\n                    initBoxOffice(obj);\n                }\n            });\n        }\n\n        //初始化总体票房\n        function initBoxOffice(obj){\n            console.log(obj);\n            var TempLength;\n            if(obj.sort.length>9){\n                TempLength = 9;\n            }\n            else{\n                TempLength = obj.sort.length;\n            }\n            var BoxOffice = $(\".boxOffice\");\n            for(var i=0;i<TempLength;i++){\n                if(i==0){\n                    BoxOffice.append(\n                        \"<li class=\\\"ranking-item ranking-top ranking-index-1\\\">\" +\n                            \"<a href=\\\"./movieDetail.jsp?movie_id=\" + obj.sort[i].movie_id + \"\\\" target=\\\"_blank\\\">\" +\n                                \"<div class=\\\"ranking-top-left\\\">\" +\n                                    \"<i class=\\\"ranking-top-icon\\\"></i>\" +\n                                    \"<img class=\\\"ranking-imgs  default-img\\\" src=\\\"\" + obj.sort[i].movie_picture + \"\\\">\" +\n                                \"</div>\" +\n                                \"<div class=\\\"ranking-top-right\\\">\" +\n                                    \"<div class=\\\"ranking-top-right-main\\\">\" +\n                                        \"<span class=\\\"ranking-top-moive-name\\\">\" + obj.sort[i].movie_cn_name + \"</span>\" +\n                                        \"<p class=\\\"ranking-top-wish\\\">\" +\n                                            \"<span class=\\\"stonefont\\\">\" + obj.sort[i].movie_boxOffice + \"</span>万\" +\n                                        \"</p>\" +\n                                    \"</div>\" +\n                                \"</div>\" +\n                            \"</a>\" +\n                        \"</li>\"\n                    );\n\n                }\n                else{\n                    BoxOffice.append(\n                        \"<li class=\\\"ranking-item ranking-index-4\\\">\" +\n                            \"<a href=\\\"./movieDetail.jsp?movie_id=\" + obj.sort[i].movie_id + \"\\\" target=\\\"_blank\\\">\" +\n                                \"<span class=\\\"normal-link\\\">\" +\n                                    \"<i class=\\\"ranking-index ranking-index-\"+(i+1)+\"\\\">\" + (i+1) + \"</i>\" +\n                                    \"<span class=\\\"ranking-movie-name\\\">\" + obj.sort[i].movie_cn_name + \"</span>\" +\n                                    \"<span class=\\\"ranking-num-info\\\">\" +\n                                        \"<span class=\\\"stonefont\\\">\" + obj.sort[i].movie_boxOffice + \"</span>万\" +\n                                    \"</span>\" +\n                                \"</span>\" +\n                            \"</a>\" +\n                        \"</li>\"\n                    );\n                }\n            }\n        }\n\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/manage.jsp",
    "content": "<%@page import=\"com.entity.User\"%>\n<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<%\n\tUser user = (User)request.getSession().getAttribute(\"user\");\n\tif(user == null){\n\t\tresponse.sendRedirect(\"./mainPage.jsp\");\n\t}else{\n        if(user.getUser_role() != 1){\n            response.sendRedirect(\"./mainPage.jsp\");\n        }\n    }\n%>\n<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/manage.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/echarts.js\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-后台管理</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 110px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"container\">\n        <div class=\"contents\">\n            <div class=\"nav-next\">\n                <div class=\"nav-title\">\n                    <h3>后台管理</h3>\n                </div>\n                <a class=\"cardId\">用户管理</a>\n                <a class=\"cardId\">电影管理</a>\n                <a class=\"cardId\">场次管理</a>\n                <a class=\"cardId\">评论管理</a>\n                <a class=\"cardId\">订单管理</a>\n                <a class=\"cardId\">票房统计</a>\n            </div>\n            <div class=\"nav-body\">\n                <!-- 用户管理 -->\n                <div class=\"one card\" style=\"display: block;\">\n                    <div>\n                        <div class=\"title\">用户管理</div>\n                        <hr/>\n                    </div>\n                    <!-- 用户列表 -->\n                    <div class=\"userlist\">\n                        <table class=\"layui-hide\" id=\"user_table_id\" lay-filter=\"UserTable\" style=\"margin-right: 5%;\"></table>\n                    </div>\n                </div>\n                <!-- 电影管理 -->\n                <div class=\"two card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">电影管理</div>\n                        <hr/>\n                    </div>\n                    <div class=\"main-inner\">\n                        <div class=\"addMovie\">\n                            <img alt=\"\" src=\"../static/images/addMovie.png\" onclick=\"addConfirm(-1)\">\n                            <span>添加电影</span>\n                        </div>\n                        <div class=\"movie-grid\">\n                            <div class=\"panel-header\">\n                                <span class=\"panel-title\">\n                                </span>\n                            </div>\n                            <div class=\"panel-content\">\n                                <ul class=\"movies-list\">\n                                </ul>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n                <!-- 场次管理 -->\n                <div class=\"three card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">场次管理</div>\n                        <hr/>\n                    </div>\n                    <!-- 场次列表 -->\n                    <div class=\"schedulelist\">\n                        <table class=\"layui-hide\" id=\"schedule_table_id\" lay-filter=\"ScheduleTable\" style=\"margin-right: 5%;\"></table>\n                    </div>\n                </div>\n                <!-- 评论管理 -->\n                <div class=\"four card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">评论管理</div>\n                        <hr/>\n                    </div>\n                    <!-- 评论列表 -->\n                    <div class=\"commentlist\">\n                        <table class=\"layui-hide\" id=\"comment_table_id\" lay-filter=\"CommentTable\" style=\"margin-right: 5%;\"></table>\n                    </div>\n                </div>\n                <!-- 订单管理 -->\n                <div class=\"five card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">订单管理</div>\n                        <hr/>\n                    </div>\n                    <!-- 订单列表 -->\n                    <div class=\"ticketlist\">\n                        <table class=\"layui-hide\" id=\"ticket_table_id\" lay-filter=\"TicketTable\" style=\"margin-right: 5%;\"></table>\n                    </div>\n                </div>\n                <!-- 票房统计 -->\n                <div class=\"six card\" style=\"display: none;\">\n                    <div>\n                        <div class=\"title\">票房统计</div>\n                        <hr/>\n                    </div>\n                    <div id=\"aaa\"></div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n\n    <!--     用户管理      -->\n    <script type=\"text/html\" id=\"userbar\">\n        <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"detail\">查看</a>\n        <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\">保存</a>\n    </script>\n    <script type=\"text/html\" id=\"usertoolbar\">\n        <div class=\"layui-btn-container adduserbtn\">\n            <button class=\"layui-btn layui-btn-warm layui-btn-sm\" lay-event=\"useradd\">添加用户</button>     \n        </div>\n        <div class=\"usercheck\">\n            <input id=\"userfindtext\" type=\"text\" name=\"title\" lay-verify=\"title\" autocomplete=\"off\" placeholder=\"请输入用户账号\" class=\"layui-input\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"finduserbtn\">搜索</button> \n        </div>\n    </script>\n\n    <!--     场次管理      -->\n    <script type=\"text/html\" id=\"schedulebar\">\n        <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"detail\">查看</a>\n        <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\">下架</a>\n    </script>\n    <script type=\"text/html\" id=\"scheduletoolbar\">\n        <div class=\"layui-btn-container addbtn\">\n            <button class=\"layui-btn layui-btn-warm layui-btn-sm\" lay-event=\"scheduleadd\">添加场次</button>     \n        </div>\n        <div class=\"schedulecheck\">\n            <input id=\"scheduletext\" type=\"text\" name=\"title\" lay-verify=\"title\" autocomplete=\"off\" placeholder=\"请输入电影名\" class=\"layui-input\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"findschedulebtn\">搜索</button> \n        </div>\n        <div class=\"scheduleonall\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"scheduleonallbtn\">显示上映</button>\n        </div>\n        <div class=\"scheduledownall\">\n            <button class=\"layui-btn layui-btn-sm layui-btn-normal\" lay-event=\"scheduledownallbtn\">显示下架</button>\n        </div>\n    </script>\n    <script type=\"text/html\" id=\"scheduledownbar\">\n        <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"detail\">查看</a>\n    </script>\n\n    <!--     评论管理      -->\n    <script type=\"text/html\" id=\"commentbar\">\n        <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"detail\">查看</a>\n        <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\">保存</a>\n        <a class=\"layui-btn layui-btn-xs layui-btn-danger\" lay-event=\"delete\">删除</a>\n    </script>\n    <script type=\"text/html\" id=\"commenttoolbar\">\n        <div class=\"commentcheck\">\n            <input id=\"commentfindtext\" type=\"text\" name=\"title\" lay-verify=\"title\" autocomplete=\"off\" placeholder=\"请输入用户账号\" class=\"layui-input\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"findcommentbtn\">搜索</button>\n        </div>\n        <div class=\"commentall\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"findcommentall\">显示全部</button>\n        </div>\n    </script>\n\n    <!--     订单管理      -->\n    <script type=\"text/html\" id=\"ticketbar\">\n        <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"detail\">查看</a>\n    </script>\n    <script type=\"text/html\" id=\"tickettoolbar\">\n        <div class=\"ticketcheck\">\n            <input type=\"button\" class=\"layui-btn-primary layui-btn-sm changeticketBtn\" style=\"width:70px;\" lay-event=\"changeticketbtn\" value=\"用户帐号\">\n            <input id=\"ticketfindtext\" type=\"text\" name=\"title\" lay-verify=\"title\" autocomplete=\"off\" placeholder=\"请输入用户账号\" class=\"layui-input\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"findticketbtn\">搜索</button>\n        </div>\n        <div class=\"orderall\">\n            <button class=\"layui-btn layui-btn-sm\" lay-event=\"findorderall\">显示全部</button>\n        </div>\n        <div class=\"backorder\">\n            <button class=\"layui-btn layui-btn-sm layui-btn-normal changeorderBtn\" lay-event=\"backorderbtn\">退票审核</button>\n        </div>\n    </script>\n    <script type=\"text/html\" id=\"backticketbar\">\n        <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"detail\">查看</a>\n        <a class=\"layui-btn layui-btn-xs\" lay-event=\"pass\">通过</a>\n    </script>\n\n    \n\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var AddUserHtml;\n        var MoviesListHtml;\n        var addScheduleContent;\n        var AddMoviesHtml;\n        var ActorNum = 1;\n        var temp, flag;\n        var changeticketbtn1 = $('.changeticketBtn');\n        var selectmovieName;\n        var movieArr = [];\n        var cinemaArr = [];\n        var cinemaJsonArr = [];\n        var boxOffice = []; //票房数组\n        var movieArray = []; //电影数组\n        var movieType = []; //电影类型数组\n        var movieTypeBoxOffice = []; //电影类型票房数组\n        var type = [];\n        window.onload = function(){\n            initHeader();\n            initHtml(); //初始化html\n            initCard(); //选项卡\n            initUser(); //用户界面\n            initMovies(); //电影界面\n            initSchedule(); //场次界面\n            initComment(); //评论界面\n            initTicket();  //订单界面\n            initBoxOffice();//票房统计\n        }\n\n        //选项卡\n        function initCard(){\n            var aArr = $(\".nav-next\").find(\".cardId\");\n            var divArr = $(\".nav-body\").find(\".card\");\n            if(localStorage.getItem(\"cardId\")==null){\n                localStorage.setItem(\"cardId\",0);\n            }\n            for(var i=0; i<aArr.length; i++){\n                aArr[i].index = i;\n                aArr[i].onclick = function(){\n                    localStorage.setItem(\"cardId\",this.index);\n                    for(var j=0;j<divArr.length;j++){\n                        divArr[j].style.display = \"none\";\n                        aArr[j].style.cssText = \"background-color: #f4f3f4; color: #333;\";\n                    }\n                    divArr[this.index].style.display = \"block\";\n                    aArr[this.index].style.cssText = \"background-color: #ed3931; color: #fff;\";\n                }\n            }\n            for(var p=0;p<aArr.length;p++){\n                divArr[p].style.display = \"none\";\n                aArr[p].style.cssText = \"background-color: #f4f3f4; color: #333;\";\n                if(localStorage.getItem(\"cardId\",this.index)==p){\n                    divArr[p].style.display = \"block\";\n                    aArr[p].style.cssText = \"background-color: #ed3931; color: #fff;\";\n                }\n            }\n        }\n        //初始化html\n        function initHtml(){\n            AddUserHtml =\n            \"<h3 class=\\\"addusertitle\\\">用户信息</h3>\" +\n            \"<div class=\\\"layui-form-item\\\">\" +\n                \"<label class=\\\"layui-form-label\\\">账号</label>\" +\n                \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                    \"<input id=\\\"user_name\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"username\\\" class=\\\"layui-input\\\">\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"layui-form-item\\\">\" +\n                \"<label class=\\\"layui-form-label\\\">密码</label>\" +\n                \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                    \"<input id=\\\"user_pwd\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"password\\\" class=\\\"layui-input\\\">\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"layui-form-item\\\">\" +\n                \"<label class=\\\"layui-form-label\\\">邮箱</label>\" +\n                \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                    \"<input id=\\\"user_email\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"email\\\" class=\\\"layui-input\\\">\" +\n                \"</div>\" +\n            \"</div>\";\n\n            AddMoviesHtml =\n            \"<h3 class=\\\"addusertitle\\\">电影信息</h3>\" +\n            \"<div class=\\\"textside\\\">\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">电影名</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_cn_name\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieCnName\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">电影外名</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_fg_name\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieFgName\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">导演</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_director\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieDirector\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\" style=\\\"display:inline-block;\\\">演职人员</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\" style=\\\"display:inline-block; margin-left: 10px !important; width: 118px;\\\">\" +\n                        \"<input id=\\\"movie_actor1\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieActor1\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                    \"<span style=\\\"margin-left:10px\\\">饰</span>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\" style=\\\"display:inline-block; margin-left: 10px !important; width: 118px;\\\">\" +\n                        \"<input id=\\\"movie_role1\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieRole1\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                    \"<button type=\\\"button\\\" class=\\\"layui-btn layui-btn-xs\\\" onclick=\\\"addActor()\\\">+</button>\" +\n                    \"<button type=\\\"button\\\" class=\\\"layui-btn layui-btn-xs\\\" onclick=\\\"deleteActor()\\\">-</button>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item temp\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">电影详情</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<textarea id=\\\"movie_detail\\\" placeholder=\\\"MovieDetail\\\" class=\\\"layui-textarea\\\"></textarea>\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">电影时长</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_duration\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieDuration\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">电影类型</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_type\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieType\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">上映时间</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_releaseDate\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieReleaseDate\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label\\\">制片地区</label>\" +\n                    \"<div class=\\\"layui-input-block addusertext\\\">\" +\n                        \"<input id=\\\"movie_country\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieCountry\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"pictureside\\\">\" +\n                \"<div class=\\\"layui-upload\\\">\" +\n                    \"<p class=\\\"movie-picture\\\">电影海报</p>\" +\n                    \"<div class=\\\"layui-upload-list\\\">\" +\n                        \"<img class=\\\"layui-upload-img\\\" id=\\\"demo1\\\">\" +\n                        \"<p id=\\\"demoText\\\"></p>\" +\n                    \"</div>\" +\n                    \"<a href=\\\"javascript:;\\\" class=\\\"file\\\">选择文件\" +\n                        \"<input type=\\\"file\\\" name=\\\"file\\\" id=\\\"file\\\">\" +\n                    \"</a>\" +\n                \"</div>\" +\n            \"</div>\";\n\n\n            addScheduleContent =\n            \"<h3 class=\\\"addtitle\\\">场次信息</h3>\" +\n            \"<div class=\\\"layui-form-item schedule-div aaaaaaa\\\">\" +\n                \"<label class=\\\"scheduleLabel\\\">电影</label>\" +\n                \"<div class=\\\"layui-form layui-input-inline addselect drop-cinema\\\" lay-filter=\\\"selectMovie\\\">\" + \n                    \"<select id=\\\"select_movie_name\\\" name=\\\"modules\\\" lay-verify=\\\"required\\\" lay-search=\\\"\\\">\" +\n                        \"<option>选择电影</option>\" +\n                    \"</select>\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"layui-form-item schedule-div\\\">\" +\n                \"<label class=\\\"scheduleLabel\\\">影院</label>\" +\n                \"<div class=\\\"layui-form layui-input-inline addselect drop-cinema\\\">\" + \n                    \"<select id=\\\"select_cinema_name\\\" name=\\\"modules\\\" lay-verify=\\\"required\\\" lay-search=\\\"\\\" lay-filter=\\\"selectCinema\\\">\" +\n                        \"<option >选择影院</option>\" +\n                    \"</select>\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"layui-form-item schedule-div\\\">\" +\n                \"<label class=\\\"scheduleLabel\\\">放映厅</label>\" +\n                \"<div class=\\\"layui-form layui-input-inline addselect drop-hall\\\" lay-filter=\\\"select\\\">\" + \n                    \"<select id=\\\"select_schedule_hall\\\" name=\\\"modules\\\" lay-verify=\\\"required\\\" lay-search=\\\"\\\">\" +\n                        \"<option>选择放映厅</option>\" +\n                    \"</select>\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"layui-form-item schedule-div\\\">\" +\n                \"<label class=\\\"scheduleLabel\\\">场次时间</label>\" +\n                \"<div class=\\\"layui-input-inline addselect\\\">\" +\n                    \"<input type=\\\"text\\\" class=\\\"layui-input\\\" id=\\\"schedule_startTime_Text\\\" placeholder=\\\"yyyy-MM-dd HH:mm\\\">\" +\n                \"</div>\" +\n            \"</div>\" +\n            \"<div class=\\\"layui-form-item schedule-div\\\">\" +\n                \"<label class=\\\"scheduleLabel\\\">价格</label>\" +\n                \"<div class=\\\"layui-input-inline addselect\\\">\" +\n                    \"<input id=\\\"schedule_price_Text\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"money\\\" class=\\\"layui-input\\\">\" +\n                \"</div>\" +\n            \"</div>\";\n        }\n\n        //初始化用户管理界面\n        function initUser(){\n            var actionUrl = \"\";\n            //用户列表\n            layui.use(['laypage', 'layer', 'table'], function(){\n                var laypage = layui.laypage;\n                var layer = layui.layer;\n                var table = layui.table;\n                table.render({\n                    elem: '#user_table_id'\n                    ,url: url + '/user/findAllUser'\n                    ,method: 'post'\n                    ,toolbar: '#usertoolbar'\n                    ,title: '用户列表'\n                    ,cols: [[\n                        {field:'user_id', title:'用户ID', width:102, unresize: true, sort: true}\n                        ,{field:'user_name', title:'用户账号', width:270, unresize: true,sort: true}\n                        ,{field:'user_pwd', title:'密码', width:270, unresize: true, edit: \"text\"}\n                        ,{field:'user_email', title:'邮箱', width:270, unresize: true, sort: true, edit: \"text\"}\n                        ,{title:'操作', width:300, unresize: true, align:'center', toolbar: '#userbar'}\n                    ]]\n                    ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                        ,curr: 1 //设定初始在第 1 页\n                        ,groups: 5 //只显示 5 个连续页码\n                        ,first: false //显示首页\n                        ,last: false //显示尾页\n                        ,limits: [10,15,20]\n                    }\n                    ,response: {\n                        statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                    }\n                    ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                        return {\n                            \"code\": res.code, //解析接口状态\n                            \"msg\": res.msg, //解析提示文本\n                            \"count\": res.count, //解析数据长度\n                            \"data\": res.data //解析数据列表\n                        };\n                    }\n                });\n                //监听工具条\n                table.on('tool(UserTable)', function(obj){\n                    var data = obj.data;\n                    if(obj.event === 'detail'){\n                        layer.msg('ID：'+ data.user_id + '</br>账号：'+ data.user_name + '</br>密码：'+ data.user_pwd  + '</br>邮箱：'+ data.user_email, {offset: clientHeight/4,area: '300px;'});\n                    }\n                    else if(obj.event === 'edit'){\n                        layer.alert('确定要对id为“'+ JSON.stringify(data.user_id) + '”的用户修改进行保存吗？',{icon: 0,offset: clientHeight/5},\n                            function () {\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/user/updateUser\",\n                                    dataType:'json',\n                                    data: {\n                                        user_id: data.user_id,\n                                        user_name: data.user_name,\n                                        user_pwd: data.user_pwd,\n                                        user_email: data.user_email,\n                                    },\n                                    success:function (date) {\n                                        if(date == \"success\"){\n                                            layer.alert('修改成功！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert('用户名已存在，修改失败！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                        );\n                    }\n                });\n                //监听头工具条\n                table.on('toolbar(UserTable)', function(obj){\n                    var checkStatus = table.checkStatus(obj.config.id);\n                    switch(obj.event){\n                        case 'useradd':\n                            //添加用户\n                            layer.open({\n                                type: 1\n                                ,title: \"添加用户\" //不显示标题栏\n                                ,closeBtn: false\n                                ,area: '400px;'\n                                ,shade: 0.8\n                                ,offset: clientHeight/5\n                                ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                                ,btn: ['确认添加', '取消']\n                                ,yes: function(){\n                                    var user_name = $('#user_name').val(),\n                                        user_pwd = $('#user_pwd').val()\n                                        user_email = $('#user_email').val();\n                                    if((user_name == \"\") || (user_pwd == \"\") || (user_email == \"\")){\n                                        layer.alert('添加信息不能存在空，添加失败！',{icon: 0,offset: clientHeight/5},\n                                            function (){\n                                                layer.close(layer.index);\n                                            }\n                                        );\n                                    }\n                                    else{\n                                        $.ajax({\n                                            type:'post',\n                                            url: url + \"/user/register\",\n                                            dataType:'json',\n                                            data: {\n                                                user_name: user_name,\n                                                user_pwd: user_pwd,\n                                                user_email: user_email,\n                                            },\n                                            success:function (date) {\n                                                if(date == \"success\"){\n                                                    layer.alert('添加成功！',{icon: 0,offset: clientHeight/5},\n                                                        function (){\n                                                            layer.closeAll();\n                                                            location.reload();\n                                                        }\n                                                    );\n                                                }else{\n                                                    layer.alert('用户名已存在，添加失败！',{icon: 0,offset: clientHeight/5},\n                                                        function (){\n                                                            layer.closeAll();\n                                                        }\n                                                    );\n                                                }\n                                            }\n                                        });\n                                    }\n\n                                }\n                                ,btnAlign: 'c'\n                                ,moveType: 0 //拖拽模式，0或者1\n                                ,content: AddUserHtml\n                                ,success: function(layero){\n                                    var btn = layero.find('.layui-layer-btn');\n                                    btn.find('.layui-layer-btn0').attr({\n                                    });\n                                }\n                            });\n                        break;\n                        case 'finduserbtn':\n                            var user_name = $('#userfindtext').val();\n                            table.reload('user_table_id', {\n                                url: url + '/user/findUserInfosByName'\n                                ,method: \"POST\"\n                                ,where: {\n                                    user_name: user_name\n                                }\n                                ,page: {\n                                    curr: 1 //重新从第 1 页开始\n                                }\n                            });\n                        break;\n                            \n                    };\n                });\n            });\n        }\n\n        //初始化电影管理界面\n        function initMovies(){\n            var MoviesNum = $(\".two\").find(\".panel-title\");\n            var MovieLi =  $(\".two\").find(\".movies-list\");\n\n            $.ajax({\n                type:'post',\n                url: url + \"/movie/findAllMovies\",\n                dataType:'json',\n                data: {},\n                success:function (obj) {\n                    console.log(obj);\n                    MoviesNum.append(\"<span class=\\\"textcolor_red\\\">正在热映（\" + obj.data.length + \"部）</span>\");\n                    for(var i=0;i<obj.data.length;i++){\n                        MoviesListHtml =\n                        \"<li>\" +\n                            \"<div class=\\\"movie-item\\\">\" +\n                                \"<a href=\\\"javascript:void(0)\\\" target=\\\"_blank\\\" data-act=\\\"playingMovie-click\\\" data-val=\\\"\"+ obj.data[i].movie_id +\"\\\">\" +\n                                    \"<div class=\\\"movie-poster\\\">\" +\n                                        \"<img src=\\\"\"+ obj.data[i].movie_picture +\"\\\" onclick=\\\"movieDetail(\"+obj.data[i].movie_id+\")\\\">\" +\n                                        \"<div class=\\\"movie-overlay movie-overlay-bg\\\">\" +\n                                            \"<div class=\\\"movie-info\\\">\" +\n                                                \"<div class=\\\"movie-score\\\"><i class=\\\"integer\\\">\"+ obj.data[i].movie_score +\"</i></div>\" +\n                                                \"<div class=\\\"movie-title movie-title-padding\\\" title=\\\"\\\">\"+ obj.data[i].movie_cn_name +\"</div>\\\"\" +\n                                            \"</div>\" +\n                                        \"</div>\" +\n                                    \"</div>\" +\n                                \"</a>\" +\n                                \"<div class=\\\"moive-btn\\\">\" +\n                                    \"<div class=\\\"movies-detail movie-detail-strong movie-sale\\\">\" +\n                                        \"<a class=\\\"active\\\" onclick=\\\"addConfirm(\"+ obj.data[i].movie_id +\")\\\" target=\\\"_blank\\\" data-act=\\\"salePlayingMovie-click\\\" data-val=\\\"\\\">修改</a>\" +\n                                    \"</div>\" +\n                                    \"<div class=\\\"movies-detail movie-detail-strong movie-sale\\\">\" +\n                                        \"<span id=\\\"deleteId\\\" style=\\\"display:none;\\\">${u.id}</span>\" +\n                                        \"<a class=\\\"active\\\" onclick=\\\"deleteConfirm(\"+ obj.data[i].movie_id +\")\\\" data-act=\\\"salePlayingMovie-click\\\" id=\\\"delete\\\">下架</a>\" +\n                                    \"</div>\" +\n                                \"</div>\" +\n                            \"</div>\" +\n                        \"</li>\";\n                        MovieLi.append(MoviesListHtml);\n                    }\n                }\n            });\n\n\n        }\n        function movieDetail(movie_id){\n            window.open(\"./movieDetail.jsp?movie_id=\" + movie_id);\n        }\n        //电影添加&修改点击事件\n        function addConfirm(movie_id){\n            var file;\n            var formData = new FormData();\n            var tempurl;\n            //添加电影\n            if(movie_id == -1){\n                tempurl = \"/movie/addMovie\";\n                temp = \"添加\";\n                flag = 0;\n            }\n            //修改电影\n            else{\n                tempurl = \"/movie/updateMovie\";\n                temp = \"修改\";\n                flag = 1;\n            }\n            layui.use(['laypage', 'layer', 'table'], function(){\n                var laypage = layui.laypage;\n                var layer = layui.layer;\n                var table = layui.table\n                //电影添加\n                layer.open({\n                    type: 1\n                    ,title: temp + \"电影\" //不显示标题栏\n                    ,closeBtn: false\n                    ,area: '750px;'\n                    ,shade: 0.8\n                    ,offset: clientHeight/20\n                    ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                    ,btn: ['确认' + temp, '取消']\n                    ,yes: function(){\n                        var movie_cn_name = $('#movie_cn_name').val(),\n                            movie_fg_name = $('#movie_fg_name').val(),\n                            movie_director = $('#movie_director').val(),\n                            movie_actor = \"\",\n                            movie_detail = $('#movie_detail').val(),\n                            movie_duration = $('#movie_duration').val(),\n                            movie_type = $('#movie_type').val(),\n                            movie_releaseDate = $('#movie_releaseDate').val(),\n                            movie_country = $('#movie_country').val();\n                        for(var i = 1;i<(ActorNum+1);i++){\n                            movie_actor += $(\"#movie_actor\" + i).val() + \":\";\n                            if(i==ActorNum){\n                                movie_actor += $(\"#movie_role\" + i).val();\n                            }\n                            else{\n                                movie_actor += $(\"#movie_role\" + i).val() + \",\";\n                            }\n                        }\n                        if((movie_cn_name == \"\") || (movie_director == \"\") || (movie_actor == \"\") ||\n                            (movie_detail == \"\") || (movie_duration == \"\") || (movie_type == \"\") || \n                            (movie_fg_name == \"\") || (movie_releaseDate == \"\") || (movie_country == \"\")){\n                            layer.alert(temp + '信息不能存在空，' + temp + '失败！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.close(layer.index);\n                                }\n                            );\n                        }\n                        //添加\n                        if(flag == 0){\n                            if(file == null){\n                                layer.alert('图片信息不能存在空，' + temp + '失败！',{icon: 0,offset: clientHeight/5},\n                                    function (){\n                                        layer.close(layer.index);\n                                    }\n                                );\n                            }else{\n                                formData.append(\"movie_cn_name\",movie_cn_name);\n                                formData.append(\"movie_fg_name\",movie_fg_name);\n                                formData.append(\"movie_director\",movie_director);\n                                formData.append(\"movie_actor\",movie_actor);\n                                formData.append(\"movie_detail\",movie_detail);\n                                formData.append(\"movie_duration\",movie_duration);\n                                formData.append(\"movie_type\",movie_type);\n                                formData.append(\"movie_releaseDate\",movie_releaseDate);\n                                formData.append(\"movie_country\",movie_country);\n                                formData.append(\"file\",file);\n                                $.ajax({\n                                    type:'post',\n                                    url: url + tempurl,\n                                    data: formData,\n                                    processData: false,\n                                    contentType: false,\n                                    success:function (result) {\n                                        var obj = eval('(' + result + ')');\n                                        if(obj.code == 0){\n                                            layer.alert(temp + '成功！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert(temp + '失败！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                           // 修改电影\n                        } else{\n                            if(file != null){\n                                formData.append(\"file\",file);\n                            }\n                            formData.append(\"movie_cn_name\",movie_cn_name);\n                            formData.append(\"movie_fg_name\",movie_fg_name);\n                            formData.append(\"movie_director\",movie_director);\n                            formData.append(\"movie_actor\",movie_actor);\n                            formData.append(\"movie_detail\",movie_detail);\n                            formData.append(\"movie_duration\",movie_duration);\n                            formData.append(\"movie_type\",movie_type);\n                            formData.append(\"movie_releaseDate\",movie_releaseDate);\n                            formData.append(\"movie_country\",movie_country);\n                            formData.append(\"movie_id\",movie_id);\n                            $.ajax({\n                                type:'post',\n                                url: url + tempurl,\n                                data: formData,\n                                processData: false,\n                                contentType: false,\n                                success:function (result) {\n                                    var obj = eval('(' + result + ')');\n                                    if(obj.code == 0){\n                                        layer.alert(temp + '成功！',{icon: 0,offset: clientHeight/5},\n                                            function (){\n                                                layer.closeAll();\n                                                location.reload();\n                                            }\n                                        );\n                                    }else{\n                                        layer.alert(temp + '失败！',{icon: 0,offset: clientHeight/5},\n                                            function (){\n                                                layer.closeAll();\n                                            }\n                                        );\n                                    }\n                                }\n                            });\n                        }\n                    }\n                    ,btnAlign: 'c movie-last'\n                    ,moveType: 0 //拖拽模式，0或者1\n                    ,content: AddMoviesHtml\n                    ,success: function(layero){\n                        if(flag == 1){\n                            var TextSide = $(\".textside\").find(\".temp\");\n                            var StrActor,StrRole;            \n                            $.ajax({\n                                type:'post',\n                                url: url + \"/movie/findMovieById\",\n                                dataType:'json',\n                                data: {\n                                    movie_id: movie_id\n                                },\n                                success:function (obj) {\n                                    $('#movie_cn_name').val(obj.data.movie_cn_name);\n                                    $('#movie_director').val(obj.data.movie_director);\n                                    ActorTemp = obj.data.movie_actor;\n                                    $('#movie_detail').val(obj.data.movie_detail);\n                                    $('#movie_duration').val(obj.data.movie_duration);\n                                    $('#movie_type').val(obj.data.movie_type);\n                                    $('#movie_fg_name').val(obj.data.movie_fg_name);\n                                    $('#movie_releaseDate').val(obj.data.releaseDate);\n                                    $('#movie_country').val(obj.data.movie_country);\n                                    $('#demo1').attr('src', obj.data.movie_picture);\n\n                                    StrActor = ActorTemp.split(',');\n                                    $('#movie_actor1').val(StrActor[0].split(':')[0]);\n                                    $('#movie_role1').val(StrActor[0].split(':')[1]);\n                                    for(var i = 1;i<StrActor.length;i++){\n                                        StrRole = StrActor[i].split(':');\n                                        TextSide.before(\n                                            \"<div class=\\\"layui-form-item\\\">\" +\n                                                \"<label class=\\\"layui-form-label\\\" style=\\\"display:inline-block;\\\">人员\" + (i+1) + \"</label>\" +\n                                                \"<div class=\\\"layui-input-block addusertext actor\\\" style=\\\"display:inline-block; margin-left: 10px !important; width: 118px;\\\">\" +\n                                                    \"<input id=\\\"movie_actor\" + (i+1) + \"\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieActor\" + (i+1) + \"\\\" class=\\\"layui-input\\\">\" +\n                                                \"</div>\" +\n                                                \"<span style=\\\"margin-left:10px\\\">饰</span>\" +\n                                                \"<div class=\\\"layui-input-block addusertext\\\" style=\\\"display:inline-block; margin-left: 10px !important; width: 118px;\\\">\" +\n                                                    \"<input id=\\\"movie_role\" + (i+1) + \"\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieRole\" + (i+1) + \"\\\" class=\\\"layui-input\\\">\" +\n                                                \"</div>\" +\n                                            \"</div>\"\n                                        );\n                                        $('#movie_actor'+(i+1)).val(StrRole[0]);\n                                        $('#movie_role'+(i+1)).val(StrRole[1]);\n                                    }\n                                    ActorNum = StrActor.length;\n                                }\n                            });\n                        }\n                        else{\n                            ActorNum = 1;\n                        }\n                        //图片上传\n                        layui.use('upload', function(){\n                            var $ = layui.jquery\n                            ,upload = layui.upload;         \n                            //普通图片上传\n                            var uploadInst = upload.render({\n                                elem: '#file'\n                                ,auto: false\n                                , choose: function (obj) {\n                                    //预读本地文件\n                                    obj.preview(function (index, file, result) {\n                                        $('#demo1').attr('src', result); //图片链接（base64）\n                                    })\n                                    file = $('#file')[0].files[0];\n                                }\n                            });\n                        });\n                    }\n                });\n            });\n        }\n        //电影下架点击事件\n        function deleteConfirm(movie_id){\n            console.log(movie_id);\n            layui.use(['layer'], function(){\n                var layer = layui.layer;\n                layer.alert('确定要对id为“'+ movie_id + '”的电影修改进行下架吗？',{icon: 0,offset: clientHeight/5},\n                    function () {\n                        $.ajax({\n                            type:'post',\n                            url: url + \"/movie/deleteMovie\",\n                            dataType:'json',\n                            data: {\n                                movie_id: movie_id,\n                            },\n                            success:function (date) {\n                                if(date.code == 0){\n                                    layer.alert('下架成功！',{icon: 0,offset: clientHeight/5},\n                                        function (){\n                                            layer.closeAll();\n                                            location.reload();\n                                        }\n                                    );\n                                }else{\n                                    layer.alert('下架失败！',{icon: 0,offset: clientHeight/5},\n                                        function (){\n                                            layer.closeAll();\n                                        }\n                                    );\n                                }\n                            }\n                        });\n                    }\n                );\n            });\n        }\n        //电影添加演员\n        function addActor(){\n            var TextSide = $(\".textside\").find(\".temp\");\n            if(ActorNum<5){\n                ActorNum++;\n                TextSide.before(\n                    \"<div class=\\\"layui-form-item\\\">\" +\n                        \"<label class=\\\"layui-form-label\\\" style=\\\"display:inline-block;\\\">人员\" + ActorNum + \"</label>\" +\n                        \"<div class=\\\"layui-input-block addusertext actor\\\" style=\\\"display:inline-block; margin-left: 10px !important; width: 118px;\\\">\" +\n                            \"<input id=\\\"movie_actor\" + ActorNum + \"\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieActor\" + ActorNum + \"\\\" class=\\\"layui-input\\\">\" +\n                        \"</div>\" +\n                        \"<span style=\\\"margin-left:10px\\\">饰</span>\" +\n                        \"<div class=\\\"layui-input-block addusertext\\\" style=\\\"display:inline-block; margin-left: 10px !important; width: 118px;\\\">\" +\n                            \"<input id=\\\"movie_role\" + ActorNum + \"\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" autocomplete=\\\"off\\\" placeholder=\\\"MovieRole\" + ActorNum + \"\\\" class=\\\"layui-input\\\">\" +\n                        \"</div>\" +\n                    \"</div>\"\n                );\n            }\n            else{\n                layui.use(['laypage', 'layer'], function(){\n                var laypage = layui.laypage;\n                var layer = layui.layer;\n                    layer.alert('最多只能存在5个演职人员！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.close(layer.index);\n                        }\n                    );\n                });\n            }\n        }\n        //电影删除演员\n        function deleteActor(){\n            console.log(ActorNum);\n            if(ActorNum>1){\n                var TextSide = $(\".textside\").find(\".layui-form-item\");\n                TextSide[(ActorNum+2)].remove();\n                ActorNum--;\n            }\n            else{\n                layui.use(['laypage', 'layer'], function(){\n                var laypage = layui.laypage;\n                var layer = layui.layer;\n                    layer.alert('最少要存在1个演职人员！',{icon: 0,offset: clientHeight/5},\n                        function (){\n                            layer.close(layer.index);\n                        }\n                    );\n                });\n            }\n        }\n\n        //初始化场次管理界面      (未完成)\n        function initSchedule(){\n            //场次列表\n            layui.use(['table'], function(){\n                var table = layui.table;\n                table.render({\n                    id: \"ScheduleTable\"\n                    ,elem: '#schedule_table_id'\n                    ,url: url + ''\n                    ,method: 'post'\n                    ,toolbar: '#scheduletoolbar'\n                    ,title: '场次列表'\n                    ,cols: [[\n                        {field:'schedule_id', title:'ID', width:102, unresize: true, sort: true}\n                        ,{field:'schedule_cinema', title:'电影院', width:270, unresize: true,sort: true}\n                        ,{field:'schedule_hall', title:'放映厅', width:270, unresize: true, sort: true, edit: \"text\"}\n                        ,{field:'schedule_startTime', title:'放映时间', width:270, unresize: true, sort: true, edit: \"text\"}\n                        ,{field:'schedule_price', title:'售价', width:270, unresize: true, edit: \"text\"}\n                        ,{title:'操作', width:300, unresize: true, align:'center', toolbar: '#schedulebar'}\n                    ]]\n                    ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                        ,curr: 1 //设定初始在第 1 页\n                        ,groups: 5 //只显示 5 个连续页码\n                        ,first: false //显示首页\n                        ,last: false //显示尾页\n                        ,limit: 10\n                    }\n                    ,response: {\n                        statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                    }\n                    ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                        return {\n                            \"code\": res.code, //解析接口状态\n                            \"msg\": res.msg, //解析提示文本\n                            \"count\": res.count, //解析数据长度\n                            \"data\": res.data //解析数据列表\n                        };\n                    }\n                });\n                //监听工具条\n                table.on('tool(ScheduleTable)', function(obj){\n                    var data = obj.data;\n                    if(obj.event === 'detail'){\n                        layer.msg('ID：'+ data.schedule_id + '</br>电影院：'+ data.schedule_cinema + '</br>放映厅：'+ data.schedule_hall  + '</br>放映时间：'+ data.schedule_startTime + '</br>售价：' + data.schedule_price, {offset: clientHeight/5});\n                    }\n                    else if(obj.event === 'edit'){\n                        layer.alert('确定要对id为“'+ JSON.stringify(data.schedule_id) + '”的场次修改进行保存吗？',{icon: 0,offset: clientHeight/5},\n                            function () {\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"\",\n                                    dataType:'json',\n                                    data: {\n                                        schedule_id: data.schedule_id,\n                                        schedule_cinema: data.schedule_cinema,\n                                        schedule_hall: data.schedule_hall,\n                                        schedule_startTime: data.schedule_startTime,\n                                        schedule_price: data.schedule_price,\n                                    },\n                                    success:function (date) {\n                                        if(date == \"success\"){\n                                            layer.alert('修改成功！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert('修改失败！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                        );\n                    }\n                });\n                //头工具栏事件\n                table.on('toolbar(ScheduleTable)', function(obj){\n                    var checkStatus = table.checkStatus(obj.config.id);\n                    switch(obj.event){\n                        case 'scheduleadd':\n                            //示范一个公告层\n                            layer.open({\n                                type: 1\n                                ,title: '添加场次' //不显示标题栏\n                                ,closeBtn: false\n                                ,area: '400px;'\n                                ,shade: 0.8\n                                ,offset: clientHeight/5\n                                ,id: 'scheduleadd' //设定一个id，防止重复弹出\n                                ,btn: ['确认添加', '取消']\n                                ,yes: function(){\n                                    var schedule_cinema = $('#schedule_cinema').val();;\n                                        schedule_hall = $('#schedule_hall').val();\n                                        schedule_startTime = $('#schedule_startTime').val();\n                                        schedule_price = $('#schedule_price').val();\n                                    if((schedule_cinema == \"直接选择或搜索选择\") || (schedule_hall == \"直接选择或搜索选择\") || (schedule_startTime == \"\") || (schedule_price ==\"\")){\n                                        layer.alert('添加信息不能存在空，添加失败！',{icon: 0,offset: clientHeight/5},\n                                            function (){\n                                                layer.close(layer.index);\n                                            }\n                                        );\n                                    }\n                                    else{\n                                        layer.alert(schedule_cinema +'</br>'+ schedule_hall + '</br>'+ schedule_startTime + '</br>'+ schedule_price,{icon: 0,offset: clientHeight/5},\n                                            function (){\n                                                layer.close(layer.index);\n                                            }\n                                        );\n                                        // $.ajax({\n                                        //     type:'post',\n                                        //     url: url + \"\",\n                                        //     dataType:'json',\n                                        //     data: {\n                                        //         schedule_cinema:schedule_cinema,\n                                        //         schedule_hall:schedule_hall,\n                                        //         schedule_startTime:schedule_startTime,\n                                        //         schedule_price:schedule_price,\n                                        //     },\n                                        //     success:function (date) {\n                                        //         if(date == \"success\"){\n                                        //             layer.alert('添加成功！',{icon: 0,offset: clientHeight/5},\n                                        //                 function (){\n                                        //                     layer.closeAll();\n                                        //                     location.reload();\n                                        //                 }\n                                        //             );\n                                        //         }else{\n                                        //             layer.alert('添加失败！',{icon: 0,offset: clientHeight/5},\n                                        //                 function (){\n                                        //                     layer.closeAll();\n                                        //                 }\n                                        //             );\n                                        //         }\n                                        //     }\n                                        // });\n                                    }\n\n                                }\n                                ,btnAlign: 'c'\n                                ,moveType: 1 //拖拽模式，0或者1\n                                ,content: addScheduleContent\n                                ,success: function(layero){\n                                    layui.use(['form','laydate','layedit'], function(){\n                                        var form = layui.form, \n                                        layedit = layui.layedit, \n                                        laydate = layui.laydate;\n                                        laydate.render({\n                                          elem: '#schedule_startTime'\n                                          ,type: 'datetime'\n                                          ,format:'yyyy-MM-dd HH:mm'\n                                        });\n                                        //form.render();\n                                        form.render('select' ,'select');\n                                    });\n                                \n                                    // layer._indexTemp = layer._indexTemp||{};\n                                    // $(document).on('click','.layui-table-view .layui-select-title, .layui-layer-content .layui-select-title, .select_option_in_layer .layui-select-title'\n                                    //     ,function (event){\n                                    //     layui.stope(event);\n                                    //     top.layer.close(top.layer._indexTemp['selectInTable']);\n                                    //     var titleElem = $(this);\n                                    //     if(!titleElem.parent().hasClass('layui-form-selected')){\n                                    //         return;\n                                    //     }\n                                    //     var dlElem = titleElem.next();\n                                    //     var titleElemPosition = getPostiton(titleElem);\n                                    //     var topTemp = titleElemPosition.top + titleElem.outerHeight();\n                                    //     var leftTemp = titleElemPosition.left;\n                                    // });\n                                }\n                            });\n                        break;\n                    };\n                });\n            });\n        }\n\n        //初始化评论管理界面\n        function initComment(){\n            //评论列表\n            layui.use('table', function(){\n                var table = layui.table;\n                table.render({\n                    elem: '#comment_table_id'\n                    ,url: url + '/comment/findAllCommentsPage'\n                    ,method: 'post'\n                    ,toolbar: '#commenttoolbar'\n                    ,title: '订单列表'\n                    ,cols: [[\n                        {field:'comment_id', title:'评论编号', width:102, unresize: true, sort: true}\n                        ,{field:'comment_user', title:'用户账号', width:100, unresize: true,templet: '<div>{{d.comment_user.user_name}}</div>'}\n                        ,{field:'comment_time', title:'评论时间', width:180, unresize: true, sort: true}\n                        ,{field:'comment_content', title:'评论内容', width:590, unresize: true, edit: \"text\"}\n                        ,{title:'操作', width:240, unresize: true, align:'center', toolbar: '#commentbar'}\n                    ]]\n                    ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                        ,curr: 1 //设定初始在第 1 页\n                        ,groups: 5 //只显示 5 个连续页码\n                        ,first: false //显示首页\n                        ,last: false //显示尾页\n                        ,limits: [10,15,20]\n                    }\n                    ,response: {\n                        statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 00\n                    }\n                    ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                        return {\n                            \"code\": res.code, //解析接口状态\n                            \"msg\": res.msg, //解析提示文本\n                            \"count\": res.count, //解析数据长度\n                            \"data\": res.data //解析数据列表\n                        };\n                    }\n                });\n                //监听工具条\n                table.on('tool(CommentTable)', function(obj){\n                    var data = obj.data;\n                    if(obj.event === 'detail'){\n                        layer.msg('ID：'+ data.comment_id + '</br>账号：'+ data.comment_user.user_name + '</br>时间：'+ data.comment_time  + '</br>内容：'+ data.comment_content, {offset: clientHeight/4});\n                    }\n                    else if(obj.event === 'edit'){\n                        console.log(obj);\n                        layer.alert('确定要对id为“'+ JSON.stringify(data.comment_id) + '”的评论内容修改进行保存吗？',{icon: 0,offset: clientHeight/5},\n                            function () {\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/comment/updateComment\",\n                                    dataType:'json',\n                                    data: {\n                                        comment_id: data.comment_id,\n                                        comment_content: data.comment_content\n                                    },\n                                    success:function (date) {\n                                        if(date.code == 0){\n                                            layer.alert('修改成功！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert('修改失败！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                        );\n                    }\n                    else if(obj.event === 'delete'){\n                        layer.alert('确定要对id为“'+ JSON.stringify(data.comment_id) + '”的评论进行删除吗？',{icon: 0,offset: clientHeight/5},\n                            function () {\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/comment/deleteComemnt\",\n                                    dataType:'json',\n                                    data: {\n                                        comment_id: data.comment_id,\n                                    },\n                                    success:function (date) {\n                                        if(date.code == 0){\n                                            layer.alert('删除成功！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert('删除失败！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                        );\n                    }\n                });\n                //监听头工具条\n                table.on('toolbar(CommentTable)', function(obj){\n                    var checkStatus = table.checkStatus(obj.config.id);\n                    switch(obj.event){\n                        case 'findcommentbtn':\n                            var user_name = $('#commentfindtext').val();\n                            table.reload('comment_table_id', {\n                                url: url + '/comment/findCommentsByUserName'\n                                ,method: \"POST\"\n                                ,where: {\n                                    user_name: user_name\n                                }\n                                ,page: {\n                                    curr: 1 //重新从第 1 页开始\n                                }\n                            });\n                        break;\n                        case 'findcommentall':\n                            table.render({\n                                elem: '#comment_table_id'\n                                ,url: url + '/comment/findAllCommentsPage'\n                                ,method: 'post'\n                                ,toolbar: '#commenttoolbar'\n                                ,title: '订单列表'\n                                ,cols: [[\n                                    {field:'comment_id', title:'评论编号', width:102, unresize: true, sort: true}\n                                    ,{field:'comment_user', title:'用户账号', width:100, unresize: true,templet: '<div>{{d.comment_user.user_name}}</div>'}\n                                    ,{field:'comment_time', title:'评论时间', width:180, unresize: true, sort: true}\n                                    ,{field:'comment_content', title:'评论内容', width:590, unresize: true, edit: \"text\"}\n                                    ,{title:'操作', width:240, unresize: true, align:'center', toolbar: '#commentbar'}\n                                ]]\n                                ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                                    ,curr: 1 //设定初始在第 1 页\n                                    ,groups: 5 //只显示 5 个连续页码\n                                    ,first: false //显示首页\n                                    ,last: false //显示尾页\n                                    ,limits: [10,15,20]\n                                }\n                                ,response: {\n                                    statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 00\n                                }\n                                ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                                    return {\n                                        \"code\": res.code, //解析接口状态\n                                        \"msg\": res.msg, //解析提示文本\n                                        \"count\": res.count, //解析数据长度\n                                        \"data\": res.data //解析数据列表\n                                    };\n                                }\n                            });\n                        break;\n                    };\n                });\n            });\n        }\n\n        //初始化订单管理界面\n        function initTicket(){\n            var PageStatus=0;\n            var actionUrl = \"\";\n            //订单列表\n            layui.use('table', function(){\n                var table = layui.table;\n                table.render({\n                    elem: '#ticket_table_id'\n                    ,url: url + \"/order/findAllOrdersPage\"\n                    ,method: 'post'\n                    ,toolbar: '#tickettoolbar'\n                    ,title: '订单列表'\n                    ,cols: [[\n                        {field:'order_id', title:'订单编号', width:160,unresize:true,sort: true,fixed:'left'}\n                        ,{field:'order_user', title:'用户账号', width:100, unresize: true,templet:'<div>{{d.order_user.user_name}}</div>'}\n                        ,{field:'order_schedule', title:'场次', width:180, unresize: true,templet:'<div>{{d.order_schedule.schedule_startTime}}</div>'}\n                        ,{field:'order_position',title:'位置',width:100,unresize:true}                       \n                        ,{field:'order_schedule',title:'价格',width:80,unresize:true,templet:'<div>￥{{d.order_schedule.schedule_price}}</div>'}\n                        ,{field:'order_schedule',title:'电影',width:240,unresize:true,templet:'<div>{{d.order_schedule.schedule_movie.movie_cn_name}}</div>'}\n                        ,{field:'order_schedule', title:'影厅', width:100, unresize: true, templet:'<div>{{d.order_schedule.schedule_hall.hall_name}}</div>'}\n                        ,{field:'order_schedule',title:'影院',width:240,unresize:true,templet:'<div>{{d.order_schedule.schedule_hall.hall_cinema.cinema_name}}</div>'}\n                        ,{field:'order_state',title:'订单状态',width:100,unresize:true,align:'center',templet:function(d){if(d.order_state == 1) return '<div style=\"color:#337ab7\">完成</div>';else if(d.order_state == 0) return '<div style=\"color:#ef4238\">申请退票</div>';else return '<div style=\"color:#5cb85c\">已退票</div>';}}\n                        ,{title:'操作', width:100, unresize: true, align:'center', toolbar: '#ticketbar'}\n                    ]]\n                    ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                        ,curr: 1 //设定初始在第 1 页\n                        ,groups: 5 //只显示 5 个连续页码\n                        ,first: false //显示首页\n                        ,last: false //显示尾页\n                        ,limits: [10,15,20]\n                    }\n                    ,response: {\n                        statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                    }\n                    ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                        return {\n                            \"code\": res.code, //解析接口状态\n                            \"msg\": res.msg, //解析提示文本\n                            \"count\": res.count, //解析数据长度\n                            \"data\": res.data //解析数据列表\n                        };\n                    },\n                });\n              \n                //监听工具条\n                table.on('tool(TicketTable)', function(obj){\n                    var data = obj.data;\n                    if(obj.event === 'detail'){\n                        layer.msg('订单编号：'+ data.order_id + '&nbsp;&nbsp;&nbsp;用户：' + data.order_user.user_name + '<br>场次：'+ data.order_schedule.schedule_startTime + '&nbsp;&nbsp;&nbsp;位置：' + data.order_position + '<br>电影：《' + data.order_schedule.schedule_movie.movie_cn_name + '》&nbsp;&nbsp;&nbsp;价格：￥' + data.order_schedule.schedule_price + '<br>影院：'+ data.order_schedule.schedule_hall.hall_cinema.cinema_name + '&nbsp;&nbsp;&nbsp;影厅：' + data.order_schedule.schedule_hall.hall_name, {offset: clientHeight/4,area:['400px','140px']});\n                    }\n                    else if(obj.event === 'pass'){\n                        layer.alert('确定要通过订单编号为“' + data.order_id + '”的退票申请吗？',{icon: 0,offset: clientHeight/5},\n                            function () {\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/order/agreeForRefund\",\n                                    dataType:'json',\n                                    data: {\n                                        order_id: data.order_id\n                                    },\n                                    success:function (data) {\n                                        if(data.code == 0){\n                                            layer.alert(data.msg,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert(data.msg,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                        );\n                    }\n                });\n                //监听头工具条\n                table.on('toolbar(TicketTable)', function(obj){\n                    var checkStatus = table.checkStatus(obj.config.id);\n                    var changeticketbtn = $('.changeticketBtn');\n                    var ticketfindtext = $('#ticketfindtext');\n                    switch(obj.event){\n                        case 'findticketbtn':\n                            var url_temp;\n                            var find_temp = $('#ticketfindtext').val();\n                            find_temp = find_temp.toString();\n                            //订单管理\n                            if(PageStatus == 0){\n                                if(changeticketbtn.val()==\"订单编号\"){\n                                    url_temp = '/order/findOrderById';\n                                    table.reload('ticket_table_id', {\n                                        url: url + url_temp\n                                        ,method: \"POST\"\n                                        ,where: {\n                                            order_id: find_temp\n                                        }\n                                        ,page: {\n                                            curr: 1 //重新从第 1 页开始\n                                        }\n                                    });\n                                }\n                                else{\n                                    url_temp = '/order/findOrderByUserName';\n                                    table.reload('ticket_table_id', {\n                                        url: url + url_temp\n                                        ,method: \"POST\"\n                                        ,where: {\n                                            user_name: find_temp\n                                        }\n                                        ,page: {\n                                            curr: 1 //重新从第 1 页开始\n                                        }\n                                    });\n                                }\n                            }\n                            //退票审核\n                            else{\n                                if(changeticketbtn.val()==\"订单编号\"){\n                                    url_temp = '/order/findOrderById';\n                                    table.reload('ticket_table_id', {\n                                        url: url + url_temp\n                                        ,method: \"POST\"\n                                        ,where: {\n                                            order_id: find_temp\n                                        }\n                                        ,page: {\n                                            curr: 1 //重新从第 1 页开始\n                                        }\n                                    });\n                                }\n                                else{\n                                    url_temp = '/order/findRefundOrderByUser';\n                                    table.reload('ticket_table_id', {\n                                        url: url + url_temp\n                                        ,method: \"POST\"\n                                        ,where: {\n                                            user_name: find_temp\n                                        }\n                                        ,page: {\n                                            curr: 1 //重新从第 1 页开始\n                                        }\n                                    });\n                                }\n                            }\n                        break;\n                        case 'changeticketbtn':\n                            if(changeticketbtn.val()==\"订单编号\"){\n                                changeticketbtn.val(\"用户帐号\");\n                                ticketfindtext.attr(\"placeholder\",\"请输入用户帐号\");\n                            }\n                            else{\n                                changeticketbtn.val(\"订单编号\");\n                                ticketfindtext.attr(\"placeholder\",\"请输入订单编号\");\n                            }\n                        break;\n                        case 'findorderall':\n                            PageStatus = 0;\n                            table.render({\n                                elem: '#ticket_table_id'\n                                ,url: url + \"/order/findAllOrdersPage\"\n                                ,method: 'post'\n                                ,toolbar: '#tickettoolbar'\n                                ,title: '订单列表'\n                                ,cols: [[\n                                    {field:'order_id', title:'订单编号', width:160,unresize:true,sort: true,fixed:'left'}\n                                    ,{field:'order_user', title:'用户账号', width:100, unresize: true,templet:'<div>{{d.order_user.user_name}}</div>'}\n                                    ,{field:'order_schedule', title:'场次', width:180, unresize: true,templet:'<div>{{d.order_schedule.schedule_startTime}}</div>'}\n                                    ,{field:'order_position',title:'位置',width:100,unresize:true}                       \n                                    ,{field:'order_schedule',title:'价格',width:80,unresize:true,templet:'<div>￥{{d.order_schedule.schedule_price}}</div>'}\n                                    ,{field:'order_schedule',title:'电影',width:240,unresize:true,templet:'<div>{{d.order_schedule.schedule_movie.movie_cn_name}}</div>'}\n                                    ,{field:'order_schedule', title:'影厅', width:100, unresize: true, templet:'<div>{{d.order_schedule.schedule_hall.hall_name}}</div>'}\n                                    ,{field:'order_schedule',title:'影院',width:240,unresize:true,templet:'<div>{{d.order_schedule.schedule_hall.hall_cinema.cinema_name}}</div>'}\n                                    ,{field:'order_state',title:'订单状态',width:100,unresize:true,align:'center',templet:function(d){if(d.order_state == 1) return '<div style=\"color:#337ab7\">完成</div>';else if(d.order_state == 0) return '<div style=\"color:#ef4238\">申请退票</div>';else return '<div style=\"color:#5cb85c\">已退票</div>';}}\n                                    ,{title:'操作', width:100, unresize: true, align:'center', toolbar: '#ticketbar'}\n                                ]]\n                                ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                                    ,curr: 1 //设定初始在第 1 页\n                                    ,groups: 5 //只显示 5 个连续页码\n                                    ,first: false //显示首页\n                                    ,last: false //显示尾页\n                                    ,limits: [10,15,20]\n                                }\n                                ,response: {\n                                    statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                                }\n                                ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                                    return {\n                                        \"code\": res.code, //解析接口状态\n                                        \"msg\": res.msg, //解析提示文本\n                                        \"count\": res.count, //解析数据长度\n                                        \"data\": res.data //解析数据列表\n                                    };\n                                },\n                            });\n                        break;\n                        case 'backorderbtn':\n                            PageStatus = 1;\n                            table.render({\n                                elem: '#ticket_table_id'\n                                ,url: url + \"/order/findAllRefundOrder\"\n                                ,method: 'post'\n                                ,toolbar: '#tickettoolbar'\n                                ,title: '订单列表'\n                                ,cols: [[\n                                    {field:'order_id', title:'订单编号', width:160,unresize:true,sort: true,fixed:'left'}\n                                    ,{field:'order_user', title:'用户账号', width:100, unresize: true,templet:'<div>{{d.order_user.user_name}}</div>'}\n                                    ,{field:'order_schedule', title:'场次', width:180, unresize: true,templet:'<div>{{d.order_schedule.schedule_startTime}}</div>'}\n                                    ,{field:'order_position',title:'位置',width:100,unresize:true}                       \n                                    ,{field:'order_schedule',title:'价格',width:80,unresize:true,templet:'<div>￥{{d.order_schedule.schedule_price}}</div>'}\n                                    ,{field:'order_schedule',title:'电影',width:240,unresize:true,templet:'<div>{{d.order_schedule.schedule_movie.movie_cn_name}}</div>'}\n                                    ,{field:'order_schedule', title:'影厅', width:100, unresize: true, templet:'<div>{{d.order_schedule.schedule_hall.hall_name}}</div>'}\n                                    ,{field:'order_schedule',title:'影院',width:240,unresize:true,templet:'<div>{{d.order_schedule.schedule_hall.hall_cinema.cinema_name}}</div>'}\n                                    ,{field:'order_state',title:'订单状态',width:100,unresize:true,align:'center',templet:function(d){if(d.order_state == 1) return '<div style=\"color:#337ab7\">完成</div>';else if(d.order_state == 0) return '<div style=\"color:#ef4238\">申请退票</div>';else return '<div style=\"color:#5cb85c\">已退票</div>';}}\n                                    ,{title:'操作', width:200, unresize: true, align:'center', toolbar: '#backticketbar'}\n                                ]]\n                                ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                                    ,curr: 1 //设定初始在第 1 页\n                                    ,groups: 5 //只显示 5 个连续页码\n                                    ,first: false //显示首页\n                                    ,last: false //显示尾页\n                                    ,limits: [10,15,20]\n                                }\n                                ,response: {\n                                    statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                                }\n                                ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                                    return {\n                                        \"code\": res.code, //解析接口状态\n                                        \"msg\": res.msg, //解析提示文本\n                                        \"count\": res.count, //解析数据长度\n                                        \"data\": res.data //解析数据列表\n                                    };\n                                },\n                            });\n                        break;\n                    };\n                });\n            });\n        }\n\n         //初始化场次管理界面\n         function initSchedule(){\n            var ScheduleStatus=0; //0：上映      1：下架\n            //场次列表\n            layui.use(['table','form'], function(){\n                var table = layui.table;\n                var form = layui.form;\n                table.render({\n                    elem: '#schedule_table_id'\n                    ,url: url + '/schedule/findAllScheduleByState'\n                    ,method: 'post'\n                    ,where: {\"schedule_state\": 1}\n                    ,toolbar: '#scheduletoolbar'\n                    ,title: '场次列表'\n                    ,cols: [[\n                        {field:'schedule_id', title:'场次编号', width:100, unresize: true, sort: true}\n                        ,{field:'schedule_hall', title:'影院', width:240, unresize: true,templet:'<div>{{d.schedule_hall.hall_cinema.cinema_name}}</div>'}\n                        ,{field:'schedule_hall', title:'影院地址', width:300, unresize: true,templet:'<div>{{d.schedule_hall.hall_cinema.cinema_address}}</div>'}\n                        ,{field:'schedule_hall', title:'影厅', width:100, unresize: true, templet:'<div>{{d.schedule_hall.hall_name}}</div>'}\n                        ,{field:'schedule_movie', title:'电影', width:240, unresize: true,templet:'<div>{{d.schedule_movie.movie_cn_name}}</div>'}\n                        ,{field:'schedule_startTime', title:'放映时间', width:180, unresize: true, sort: true}\n                        ,{field:'schedule_price', title:'价格(￥)', width:100,align:'center', unresize: true}\n                        ,{field:'orderList',title:'订单数量',width:100,unresize:true,align:'center',templet:'<div>{{d.orderList.length}}</div>'}\n                        ,{field:'schedule_remain',title:'剩余票数',width:100,align:'center',unresize:true}\n                        ,{field:'orderList',title:'场次收入(￥)',width:120,align:'center',unresize:true,templet:'<div>{{d.orderList.length * d.schedule_price}}</div>'}\n                        ,{title:'操作', width:200, unresize: true, align:'center', toolbar: '#schedulebar'}\n                    ]]\n                    ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                        ,curr: 1 //设定初始在第 1 页\n                        ,groups: 5 //只显示 5 个连续页码\n                        ,first: false //显示首页\n                        ,last: false //显示尾页\n                        ,limits: [10,15,20]\n                    }\n                    ,response: {\n                        statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                    }\n                    ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                        return {\n                            \"code\": res.code, //解析接口状态\n                            \"msg\": res.msg, //解析提示文本\n                            \"count\": res.count, //解析数据长度\n                            \"data\": res.data, //解析数据列表\n                        };\n                    }\n                });\n                //监听工具条\n                table.on('tool(ScheduleTable)', function(obj){\n                    var data = obj.data;\n                    if(obj.event === 'detail'){\n                        console.log(obj);\n                        layer.msg('编号：'+ data.schedule_id + '</br>影院：'+ data.schedule_hall.hall_cinema.cinema_name + '&nbsp;&nbsp;&nbsp;放映厅：'+ data.schedule_hall.hall_name  + '</br>影院地址：'+ data.schedule_hall.hall_cinema.cinema_address + '</br>电影：'+ data.schedule_movie.movie_cn_name + '</br>场次：' + data.schedule_startTime + '&nbsp;&nbsp;&nbsp;价格：' + data.schedule_price, {offset: clientHeight/5});\n                    }\n                    else if(obj.event === 'edit'){\n                        layer.alert('确定要对id为“'+ data.schedule_id + '”的场次进行下架吗？',{icon: 0,offset: clientHeight/5},\n                            function () {\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/schedule/offlineSchedule\",\n                                    dataType:'json',\n                                    data: {\n                                        schedule_id: data.schedule_id,\n                                    },\n                                    success:function (result) {\n                                        console.log(data.schedule_id);\n                                        if(result.code == 0){\n                                            layer.alert(result.mgs,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert(result.mgs,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n                            }\n                        );\n                    }\n                });\n                //头工具栏事件\n                table.on('toolbar(ScheduleTable)', function(obj){\n                    var checkStatus = table.checkStatus(obj.config.id);\n                    switch(obj.event){\n                        case 'scheduleadd':\n                            //示范一个公告层\n                            layer.open({\n                                type: 1\n                                ,title: '添加场次' //不显示标题栏\n                                ,closeBtn: false\n                                ,area: '400px;'\n                                ,shade: 0.8\n                                ,offset: clientHeight/10\n                                ,id: 'scheduleadd' //设定一个id，防止重复弹出\n                                ,btn: ['确认添加', '取消']\n                                ,yes: function(){\n                                    console.log(\"queding\");\n                                    var select_movie_name = $('#select_movie_name').val();\n                                    var select_cinema_name = $(\"#select_cinema_name\").val();\n                                    var select_schedule_hall = $('#select_schedule_hall').val();\n                                    var schedule_startTime_Text = $(\"#schedule_startTime_Text\").val();\n                                    var schedule_price_Text = $('#schedule_price_Text').val();\n                                    if((select_movie_name == \"选择电影\") || (select_cinema_name == \"选择影院\") || (select_schedule_hall == \"选择放映厅\") ||\n                                        (schedule_startTime_Text ==\"\") || (schedule_price_Text ==\"\")){\n                                        layer.alert('添加信息不能存在空，添加失败！',{icon: 0,offset: clientHeight/5},\n                                            function (){\n                                                layer.close(layer.index);\n                                            }\n                                        );\n                                    }\n                                    else{\n                                        $.ajax({\n                                            type:'post',\n                                            url: url + \"/schedule/addSchedule\",\n                                            dataType:'json',\n                                            data: {\n                                                movie_name: select_movie_name,\n                                                cinema_name: select_cinema_name,\n                                                hall_name: select_schedule_hall,\n                                                schedule_startTime: schedule_startTime_Text,\n                                                schedule_price: schedule_price_Text,\n                                            },\n                                            success:function (result) {\n                                                if(result.code == 0){\n                                                    layer.alert(result.mgs,{icon: 0,offset: clientHeight/5},\n                                                        function (){\n                                                            layer.closeAll();\n                                                            location.reload();\n                                                        }\n                                                    );\n                                                }else{\n                                                    layer.alert(result.mgs,{icon: 0,offset: clientHeight/5},\n                                                        function (){\n                                                            layer.closeAll();\n                                                        }\n                                                    );\n                                                }\n                                            }\n                                        });\n                                    }\n                                }\n                                ,end: function(){\n                                    cinemaJsonArr = [];\n                                }\n                                ,btnAlign: 'c'\n                                ,moveType: 1 //拖拽模式，0或者1\n                                ,content: addScheduleContent\n                                ,success: function(layero){\n                                    layui.use(['form','laydate','layedit'], function(){\n                                        var form = layui.form, \n                                        layedit = layui.layedit, \n                                        laydate = layui.laydate;\n                                        laydate.render({\n                                          elem: '#schedule_startTime_Text'\n                                          ,type: 'datetime'\n                                          ,format:'yyyy-MM-dd HH:mm'\n                                        });\n                                        form.render('select' ,'select');\n                                    });\n                                    $.ajax({\n                                        type:'post',\n                                        url: url + \"/schedule/findAllSchedule\",\n                                        dataType:'json',\n                                        data: {},\n                                        success:function (objs) {\n                                            movieArr = objs.movieName;\n                                            cinemaArr = objs.cinema;\n                                            //解析json数组 简化\n                                            for(var i = 0;i < cinemaArr.length;i++){\n                                                var cinemaJson = {};\n                                                for(var key in cinemaArr[i]){\n                                                    var cinemaName = key; \n                                                    var hallArr = [];\n                                                    for(var j = 0;j < cinemaArr[i][key].length; j++){\n                                                        hallArr.push(cinemaArr[i][key][j].hall_name);\n                                                    }\n                                                    cinemaJson.cinema = key;\n                                                    cinemaJson.hallArr = hallArr;\n                                                }\n                                                cinemaJsonArr.push(cinemaJson);\n                                            }\n\n                                            console.log(cinemaJsonArr);\n                                            for(var i=0;i<movieArr.length;i++){\n                                               $(\"#select_movie_name\").append(new Option(movieArr[i]));\n                                               layui.form.render(\"select\");\n                                            }\n\n                                            for(var i=0;i<cinemaJsonArr.length;i++){\n                                                $(\"#select_cinema_name\").append(new Option(cinemaJsonArr[i].cinema));\n                                                layui.form.render(\"select\");\n                                            }\n                                        }\n                                    });\n                                }\n                            });\n                        break;\n                        case 'findschedulebtn':\n                            var find_temp = $('#scheduletext').val();\n                            //上映\n                            if(ScheduleStatus==0){\n                                table.reload('schedule_table_id', {\n                                    url: url + \"/schedule/findScheduleByMovieName\"\n                                    ,method: \"POST\"\n                                    ,where: {\n                                        movie_name: find_temp\n                                    }\n                                    ,page: {\n                                        curr: 1 //重新从第 1 页开始\n                                    }\n                                });\n                            }\n                            //下架\n                            else{\n                                table.reload('schedule_table_id', {\n                                    url: url + \"/schedule/findOffScheduleByMovieName\"\n                                    ,method: \"POST\"\n                                    ,where: {\n                                        movie_name: find_temp\n                                    }\n                                    ,page: {\n                                        curr: 1 //重新从第 1 页开始\n                                    }\n                                });\n                            }\n                        break;\n                        case 'scheduleonallbtn':\n                            ScheduleStatus = 0;\n                            table.render({\n                                elem: '#schedule_table_id'\n                                ,url: url + '/schedule/findAllScheduleByState'\n                                ,method: 'post'\n                                ,where: {\"schedule_state\": 1}\n                                ,toolbar: '#scheduletoolbar'\n                                ,title: '场次列表'\n                                ,cols: [[\n                                    {field:'schedule_id', title:'场次编号', width:100, unresize: true, sort: true}\n                                    ,{field:'schedule_hall', title:'影院', width:240, unresize: true,templet:'<div>{{d.schedule_hall.hall_cinema.cinema_name}}</div>'}\n                                    ,{field:'schedule_hall', title:'影院地址', width:300, unresize: true,templet:'<div>{{d.schedule_hall.hall_cinema.cinema_address}}</div>'}\n                                    ,{field:'schedule_hall', title:'影厅', width:100, unresize: true, templet:'<div>{{d.schedule_hall.hall_name}}</div>'}\n                                    ,{field:'schedule_movie', title:'电影', width:240, unresize: true,templet:'<div>{{d.schedule_movie.movie_cn_name}}</div>'}\n                                    ,{field:'schedule_startTime', title:'放映时间', width:180, unresize: true, sort: true}\n                                    ,{field:'schedule_price', title:'价格(￥)', width:100,align:'center', unresize: true}\n                                    ,{field:'orderList',title:'订单数量',width:100,unresize:true,align:'center',templet:'<div>{{d.orderList.length}}</div>'}\n                                    ,{field:'schedule_remain',title:'剩余票数',width:100,align:'center',unresize:true}\n                                    ,{field:'orderList',title:'场次收入(￥)',width:120,align:'center',unresize:true,templet:'<div>{{d.orderList.length * d.schedule_price}}</div>'}\n                                    ,{title:'操作', width:200, unresize: true, align:'center', toolbar: '#schedulebar'}\n                                ]]\n                                ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                                    ,curr: 1 //设定初始在第 1 页\n                                    ,groups: 5 //只显示 5 个连续页码\n                                    ,first: false //显示首页\n                                    ,last: false //显示尾页\n                                    ,limits: [10,15,20]\n                                }\n                                ,response: {\n                                    statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                                }\n                                ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                                    return {\n                                        \"code\": res.code, //解析接口状态\n                                        \"msg\": res.msg, //解析提示文本\n                                        \"count\": res.count, //解析数据长度\n                                        \"data\": res.data, //解析数据列表\n                                        \"income\": res.income //解析数据列表\n                                    };\n                                }\n                            });\n                        break;\n                        case 'scheduledownallbtn':\n                            ScheduleStatus = 1;\n                            table.render({\n                                elem: '#schedule_table_id'\n                                ,url: url + '/schedule/findAllScheduleByState'\n                                ,method: 'post'\n                                ,where: {\"schedule_state\": 0}\n                                ,toolbar: '#scheduletoolbar'\n                                ,title: '场次列表'\n                                ,cols: [[\n                                    {field:'schedule_id', title:'场次编号', width:100, unresize: true, sort: true}\n                                    ,{field:'schedule_hall', title:'影院', width:240, unresize: true,templet:'<div>{{d.schedule_hall.hall_cinema.cinema_name}}</div>'}\n                                    ,{field:'schedule_hall', title:'影院地址', width:300, unresize: true,templet:'<div>{{d.schedule_hall.hall_cinema.cinema_address}}</div>'}\n                                    ,{field:'schedule_hall', title:'影厅', width:100, unresize: true, templet:'<div>{{d.schedule_hall.hall_name}}</div>'}\n                                    ,{field:'schedule_movie', title:'电影', width:240, unresize: true,templet:'<div>{{d.schedule_movie.movie_cn_name}}</div>'}\n                                    ,{field:'schedule_startTime', title:'放映时间', width:180, unresize: true, sort: true}\n                                    ,{field:'schedule_price', title:'价格(￥)', width:100,align:'center', unresize: true}\n                                    ,{field:'orderList',title:'订单数量',width:100,unresize:true,align:'center',templet:'<div>{{d.orderList.length}}</div>'}\n                                    ,{field:'schedule_remain',title:'剩余票数',width:100,align:'center',unresize:true}\n                                    ,{field:'orderList',title:'场次收入(￥)',width:120,align:'center',unresize:true,templet:'<div>{{d.orderList.length * d.schedule_price}}</div>'}\n                                    ,{title:'操作', width:200, unresize: true, align:'center', toolbar: '#scheduledownbar'}\n                                ]]\n                                ,page: {layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局\n                                    ,curr: 1 //设定初始在第 1 页\n                                    ,groups: 5 //只显示 5 个连续页码\n                                    ,first: false //显示首页\n                                    ,last: false //显示尾页\n                                    ,limits: [10,15,20]\n                                }\n                                ,response: {\n                                    statusCode: 0 //重新规定成功的状态码为 200，table 组件默认为 0\n                                }\n                                ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据\n                                    return {\n                                        \"code\": res.code, //解析接口状态\n                                        \"msg\": res.msg, //解析提示文本\n                                        \"count\": res.count, //解析数据长度\n                                        \"data\": res.data, //解析数据列表\n                                        \"income\": res.income //解析数据列表\n                                    };\n                                }\n                            });\n                        break;\n                    };\n                });\n                //监听影院二级联动\n                form.on('select(selectCinema)',function(data){\n                    $(\"#select_schedule_hall\").empty();\n                    layui.form.render(\"select\");\n                    for(var i = 0;i < cinemaJsonArr.length;i++){\n                        if(cinemaJsonArr[i].cinema == data.value){\n                            for(var j=0;j<cinemaJsonArr[i].hallArr.length;j++){\n                                $(\"#select_schedule_hall\").append(new Option(cinemaJsonArr[i].hallArr[j]));\n                                layui.form.render(\"select\");\n                            }\n                        }\n                    }\n                });\n            });\n        }\n\n        function sortUp(a,b){\n                return a-b;\n         }\n         //初始化票房统计界面\n        function initBoxOffice(){\n            $.ajax({\n                type:'post',\n                url: url + \"/movie/findAllMovies\",\n                dataType:'json',\n                data: {},\n                //获取数据  根据类型：统计票房   type:['喜剧','动作','爱情','动画','科幻','惊悚','冒险','犯罪','悬疑'] typeIncome: []  场次管理接口 下架之后数据更新    //头像为null时 默认设置为某一张 \n                success:function (obj) {\n                    if(obj.sort.length > 10){\n                        obj.sort.length = 10;\n                    }\n                    for(var i = obj.sort.length - 1;i >= 0;i--){\n                        movieArray.push(obj.sort[i].movie_cn_name);\n                        boxOffice.push(Math.ceil(obj.sort[i].movie_boxOffice * 10000));\n                    }\n                    for(var i = 0;i < obj.type.length;i++){\n                        var typeJson = {};\n                        for(var key in obj.type[i]){\n                            movieType.push(key);\n                            movieTypeBoxOffice.push(obj.type[i][key]);\n                            var num = parseFloat(obj.type[i][key]);\n                            typeJson.value = Math.ceil(num * 10000);\n                            typeJson.name = key;\n                        }\n                        type.push(typeJson);\n                    }\n                    console.log(movieArray);\n                    console.log(boxOffice);\n                     //扇形图\n                    var aaa = $(\"#aaa\");\n                    aaa.append(\"<div id=\\\"main1\\\" style=\\\"width: 1100px;height:400px;\\\"></div>\")\n                    var myChart1 = echarts.init(document.getElementById('main1'));   \n                    option1 = {\n                        title : {\n                            text: '类型统计',\n                            x:'center'\n                        },\n                        tooltip : {\n                            trigger: 'item',\n                            formatter: \"{a} <br/>{b} : {c} ({d}%)\"\n                        },\n                        color: ['#6dd8da', '#b6a2de', '#58afed', '#9AC0CD','#ff99cc'],\n                        legend: {\n                            orient : 'vertical',\n                            x : '10%',\n                            y : '15%',\n                            data:movieType\n                        },\n                        toolbox: {\n                            show : true,\n                            feature : {\n                                mark : {show: true},\n                                dataView : {show: true, readOnly: false},\n                                magicType : {\n                                    show: true, \n                                    type: ['pie', 'funnel'],\n                                    option: {\n                                        funnel: {\n                                            x: '25%',\n                                            width: '50%',\n                                            funnelAlign: 'left',\n                                            max: 1548\n                                        }\n                                    }\n                                },\n                                restore : {show: true},\n                                saveAsImage : {show: true}\n                            }\n                        },\n                        calculable : true,\n                        series : [\n                            {\n                                name:'类型，票房',\n                                type:'pie',\n                                radius : '60%',\n                                center: ['50%', '50%'],\n                                data: type,\n                            }\n                        ]\n                    };\n                    myChart1.setOption(option1);\n\n                    //统计图\n                    var aaa = $(\"#aaa\");\n                    aaa.append(\"<div id=\\\"main2\\\" style=\\\"width: 1200px;height:450px;margin-top:100px;\\\"></div>\")\n                    var myChart2 = echarts.init(document.getElementById('main2'));  \n                    option2 = {\n                        title : {\n                            text: '电影票房排名',\n                            subtext: '排行前十'\n                        },\n                        tooltip : {\n                            trigger: 'axis'\n                        },\n                        legend: {\n                            data:['总体票房']\n                        },\n                        toolbox: {\n                            show : true,\n                            feature : {\n                                mark : {show: true},\n                                dataView : {show: true, readOnly: false},\n                                magicType: {show: true, type: ['line', 'bar']},\n                                restore : {show: true},\n                                saveAsImage : {show: true}\n                            }\n                        },\n                        calculable : true,\n                        xAxis : [\n                            {\n                                type : 'value',\n                                boundaryGap : [0, 0.01]\n                            }\n                        ],\n                        \n                        yAxis : [\n                            {\n                                type : 'category',\n                                data : movieArray,\n                            }\n                        ],\n                        series : [\n                            {\n                                name:'总体票房',\n                                type:'bar',\n                                data: boxOffice,\n                                color:'#11EEC2'\n                            },\n                        ]\n                    };\n                    myChart2.setOption(option2);\n                }\n            });\n        }\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/movieDetail.jsp",
    "content": "﻿<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/buyTickets.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/movieDetail.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-详细</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n   \n    <!-- 占位符 -->\n    <div style=\"margin-top: 80px;\"></div>\n\n    <!-- 巨幕 -->\n    <div class=\"banner2\">\n        <div class=\"wrapper clearfix\">\n            <div class=\"celeInfo-left\">\n                <div class=\"avatar-shadow\">\n                    <!-- 图片 -->\n                </div>\n            </div>\n            \n            <div class=\"celeInfo-right clearfix\">\n                <div class=\"movie-brief-container\">\n                    <!-- 上 -->\n                </div>\n                <div class=\"action-buyBtn\">\n                    <div class=\"action clearfix\" data-val=\"{movieid:42964}\">\n                        <a class=\"wish \" data-wish=\"false\" onclick=\"wantSee()\">\n                            <div>\n                                <i class=\"icon wish-icon\"></i>\n                                <span class=\"wish-msg\" data-act=\"wish-click\">想看</span>\n                            </div>\n                        </a>\n                        <a class=\"score-btn \" data-bid=\"b_rxxpcgwd\" onclick=\"giveScore()\">\n                            <div>\n                                <i class=\"icon score-btn-icon\"></i>\n                                <span class=\"score-btn-msg\" data-act=\"comment-open-click\">评分</span>\n                            </div>\n                        </a>\n                    </div>\n                </div>\n\n                <div class=\"movie-stats-container\">\n                    <div class=\"movie-index\">\n                        <p class=\"movie-index-title\">用户评分</p>\n                        <div class=\"movie-index-content score normal-score\">\n                            <span class=\"index-left info-num \">\n                                <!-- 评分 -->\n                            </span>\n                            <div class=\"index-right\">\n                                <div class=\"star-wrapper\">\n                                    <div id=\"MovieScore\"></div>\n                                </div>\n                                <span class=\"score-num\">\n                                    <!-- 评分数 -->\n                                </span>\n                            </div>\n                        </div>\n                    </div>   \n\n                    <div class=\"movie-index\">\n                        <p class=\"movie-index-title\">累计票房</p>\n                        <div class=\"movie-index-content box stonefont-num\">\n                            <!-- 票房数 -->\n                        </div>\n                    </div>\n                </div>\n\n            </div>\n        </div>\n    </div>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 50px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"main\">\n        <div class=\"main-inner main-detail\">\n            <div class=\"main-content\">\n                <div class=\"tab-container\">\n                    <div class=\"tab-title-container clearfix\">\n                        <div class=\"tab-title active\" data-act=\"tab-desc-click\">介绍</div>\n                    </div>\n\n                    <div class=\"tab-content-container\">\n                        <div class=\"tab-desc tab-content active\" data-val=\"{tabtype:'desc'}\">\n                            <!-- 剧情简介 -->\n                            <div class=\"module introduction\">\n                                <div class=\"mod-title\">\n                                    <h3>剧情简介</h3>\n                                </div>\n                            </div>\n                            <!-- 演职人员 -->\n                            <div class=\"module staringPeople\" >\n                                <div class=\"mod-title\">\n                                    <h3>演职人员</h3>\n                                </div>\n                                <div class=\"mod-content\">\n                                    <div class=\"celebrity-container clearfix\">\n                                    </div>\n                                </div>\n                            </div>\n                            <!-- 评论 -->\n                            <div class=\"module\">\n                                <div class=\"mod-title\">\n                                    <h3>热门短评</h3>\n                                </div>\n\n                                <div class=\"mod-content\">\n                                    <div class=\"comment-list-container\" data-hot=\"10\">\n                                        <ul>\n                                        </ul>\n                                    </div>\n                                    <a class=\"comment-entry\" data-act=\"comment-no-content-click\" onclick=\"writeComment()\">写短评</a>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var movie_id;\n        var ScoreHtml;\n\n        window.onload = function(){\n            initHeader();\n            initHtml(); //HTML\n            initBanner(); //巨幕\n            intitActor(); //演职人员\n            init_comment(); //评论\n        }\n\n        //初始化HTML\n        function initHtml(){\n            ScoreHtml = \n                \"<div style=\\\"text-align:center; margin:30px 0;\\\">\" +\n                    \"<div id=\\\"GiveScore\\\"></div>\" +\n                    \"<p style=\\\"color:#888;\\\">点击星星进行评分</p>\" +\n                \"</div>\"\n            ;\n            UpdateCommentHtml = \n                \"<h3 class=\\\"commenttitle\\\">评论信息</h3>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label usernametext\\\">用户帐号</label>\" +\n                    \"<div class=\\\"layui-input-block username\\\">\" +\n                        \"<input id=\\\"user_name\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" disabled=\\\"disabled\\\" style=\\\"cursor:not-allowed;\\\" autocomplete=\\\"off\\\" placeholder=\\\"username\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label commenttimetext\\\">评论时间</label>\" +\n                    \"<div class=\\\"layui-input-block commenttime\\\">\" +\n                        \"<input id=\\\"comment_time\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" disabled=\\\"disabled\\\" style=\\\"cursor:not-allowed;\\\" autocomplete=\\\"off\\\" placeholder=\\\"commenttime\\\" class=\\\"layui-input\\\">\" +\n                    \"</div>\" +\n                \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label commentcontenttext\\\">评论内容</label>\" +\n                    \"<div class=\\\"layui-input-block commentcontent\\\">\" +\n                        \"<textarea id=\\\"comment_content\\\" style=\\\"height:120px;\\\" placeholder=\\\"请输入评论内容\\\" autocomplete=\\\"off\\\" class=\\\"layui-textarea\\\" name=\\\"desc\\\" class=\\\"layui-input\\\"></textarea>\" +\n                    \"</div>\" +\n                \"</div>\"\n            ;\n            WriteCommentHtml = \n                \"<h3 class=\\\"commenttitle\\\">评论信息</h3>\" +\n                // \"<div class=\\\"layui-form-item\\\">\" +\n                //     \"<label class=\\\"layui-form-label usernametext\\\">用户帐号</label>\" +\n                //     \"<div class=\\\"layui-input-block username\\\">\" +\n                //         \"<input id=\\\"user_name_write\\\" type=\\\"text\\\" name=\\\"title\\\" lay-verify=\\\"title\\\" disabled=\\\"disabled\\\" style=\\\"cursor:not-allowed;\\\" autocomplete=\\\"off\\\" placeholder=\\\"username\\\" class=\\\"layui-input\\\">\" +\n                //     \"</div>\" +\n                // \"</div>\" +\n                \"<div class=\\\"layui-form-item\\\">\" +\n                    \"<label class=\\\"layui-form-label commentcontenttext\\\">评论内容</label>\" +\n                    \"<div class=\\\"layui-input-block commentcontent\\\">\" +\n                        \"<textarea id=\\\"comment_content_write\\\" style=\\\"height:150px;\\\" placeholder=\\\"请输入评论内容\\\" autocomplete=\\\"off\\\" class=\\\"layui-textarea\\\" name=\\\"desc\\\" class=\\\"layui-input\\\"></textarea>\" +\n                    \"</div>\" +\n                \"</div>\"\n            ;\n        }\n\n        //初始化巨幕\n        function initBanner(){\n            movie_id = getUrlParams('movie_id');\n            var avatar = $(\".avatar-shadow\");\n            var movieBriefContainer = $(\".movie-brief-container\");\n            var infoNum = $(\".info-num\");\n            var scoreNum = $(\".score-num\");\n            var stonefontNum = $(\".stonefont-num\");\n            var actionBuyBtn = $(\".action-buyBtn\");\n            var Introduction = $(\".introduction\");\n            var StonefontTemp;\n        \n            $.ajax({\n                type:'post',\n                url: url + \"/movie/findMovieById\",\n                dataType:'json',\n                data: {\n                    movie_id: movie_id\n                },\n                success:function (obj) {\n                    StonefontTemp = obj.data.movie_boxOffice;\n                    StonefontTemp += \"万\";\n                    avatar.append(\"<img class=\\\"avatar\\\" src=\\\"\" + obj.data.movie_picture + \"\\\" alt=\\\"\\\">\");\n                    movieBriefContainer.append(\n                    \"<h3 class=\\\"name\\\">\" + obj.data.movie_cn_name + \"</h3>\" +\n                    \"<div class=\\\"ename ellipsis\\\">\" + obj.data.movie_fg_name + \"</div>\" +\n                    \"<ul>\" +\n                        \"<li class=\\\"ellipsis\\\">\" + obj.data.movie_type + \"</li>\" +\n                        \"<li class=\\\"ellipsis\\\">\" + obj.data.movie_duration + \" / \" + obj.data.movie_country + \"</li>\" +\n                        \"<li class=\\\"ellipsis\\\">\" + obj.data.releaseDate + \"</li>\" +\n                    \"<ul>\");\n                    infoNum.append(\"<span class=\\\"stonefont\\\">\" + obj.data.movie_score + \"</span>\");\n                    scoreNum.append(\"<span class=\\\"stonefont\\\">\" + obj.data.movie_commentCount + \"</span>人评分\");\n                    stonefontNum.append(\"<span class=\\\"stonefont\\\">\" + StonefontTemp + \"</span>\");\n                    actionBuyBtn.append(\"<div class=\\\"moviedetail\\\"></div>\");\n                    Introduction.append(\n                        \"<div class=\\\"mod-content\\\">\" +\n                            \"<span class=\\\"dra\\\" style=\\\"font-size:16px;\\\">\" + obj.data.movie_detail + \"</span>\" +\n                        \"</div>\"\n                    );\n                    layui.use('rate', function(){\n                        var rate = layui.rate;\n                        rate.render({\n                            elem: '#MovieScore'\n                            ,value: (obj.data.movie_score / 2)\n                            ,half: true\n                            ,readonly: true\n                        })\n                    });\n                }\n            });\n        }\n        //评分\n        function giveScore(){\n            layui.use(['rate','layer'], function(){\n                var layer = layui.layer;\n                var rate = layui.rate;\n                layer.open({\n                    type: 1\n                    ,title: \"电影评分\"\n                    ,closeBtn: false\n                    ,area: '400px;'\n                    ,shade: 0.8\n                    ,offset: clientHeight/5\n                    ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                    ,btn: ['确认评分', '取消']\n                    ,yes: function(){\n                        layer.alert('感谢你的评价,祝你生活愉快！',{icon: 0,offset: clientHeight/5},\n                            function (){\n                                layer.closeAll();\n                                location.reload();\n                            }\n                        );\n                    }\n                    ,btnAlign: 'c'\n                    ,moveType: 0 //拖拽模式，0或者1\n                    ,content: ScoreHtml\n                    ,success: function(layero){\n                        rate.render({\n                            elem: '#GiveScore'\n                            ,value: 4.5\n                            ,half: true\n                            ,text: true\n                            ,setText: function(value){\n                                this.span.text(value*2+\"分\");\n                            }\n                        })\n                    }\n                });\n            });\n        }\n        //想看\n        function wantSee(){\n            layui.use(['rate','layer'], function(){\n                var layer = layui.layer;\n                var rate = layui.rate;\n                layer.alert('感谢你的支持！',{icon: 0,offset: clientHeight/5},\n                    function (){\n                        layer.closeAll();\n                        location.reload();\n                    }\n                );\n            });\n        }\n        \n        //初始化演职人员\n        function intitActor(){\n            var celebrityContainer = $(\".celebrity-container\");\n            var PosName;\n            var StrActor;\n            var StrRole;\n            var PictureUrl;\n            $.ajax({\n                type:'post',\n                url: url + \"/movie/findMovieById\",\n                dataType:'json',\n                data: {\n                    movie_id: movie_id\n                },\n                success:function (obj) {\n                    console.log(obj);\n                    PictureUrl = \"../static/images/actor/\" + obj.data.movie_cn_name + \"/director/\" + obj.data.movie_director + \".jpg\";\n                    // 导演\n                    celebrityContainer.prepend(\n                        \"<div class=\\\"celebrity-group\\\">\" +\n                            \"<div class=\\\"celebrity-type\\\">\" +\n                                \"导演\" +\n                            \"</div>\" +\n                            \"<ul class=\\\"celebrity-list clearfix\\\">\" +\n                                \"<li class=\\\"celebrity\\\">\" +\n                                    \"<a class=\\\"portrait\\\">\" +\n                                        \"<img class=\\\"default-img\\\" alt=\\\"\\\" src=\\\"\" + PictureUrl + \"\\\">\" +\n                                    \"</a>\" +\n                                    \"<div>\" +\n                                        \"<a style=\\\"text-decoration: none;\\\" class=\\\"name\\\">\" + obj.data.movie_director + \"</a>\" +\n                                    \"</div>\" +\n                                \"</li>\" +\n                            \"</ul>\" +\n                        \"</div>\" +\n                        \"<div style=\\\"width:40px; height:20px; float:left;\\\"></div>\"\n                    );\n                    StrActor = obj.data.movie_actor.split(',');\n                    for(var i = 0;i<StrActor.length;i++){\n                        StrRole = StrActor[i].split(':');\n                        PictureUrl = \"../static/images/actor/\" + obj.data.movie_cn_name + \"/actor/\" + StrRole[0] + \".jpg\";\n                        // 演员\n                        PosName=\"&nbsp\";\n                        if(i==0){\n                            PosName = \"演职人员\";\n                        }\n                        celebrityContainer.append(\n                            \"<div class=\\\"celebrity-group\\\">\" +\n                                \"<div class=\\\"celebrity-type\\\">\" +\n                                    PosName +\n                                \"</div>\" +\n                                \"<ul class=\\\"celebrity-list clearfix\\\">\" +\n                                    \"<li class=\\\"celebrity\\\">\" +\n                                        \"<a class=\\\"portrait\\\">\" +\n                                            \"<img class=\\\"default-img\\\" alt=\\\"\\\" src=\\\"\" + PictureUrl + \"\\\">\" +\n                                        \"</a>\" +\n                                        \"<div>\" +\n                                            \"<a style=\\\"text-decoration: none;\\\" class=\\\"name\\\">\" + StrRole[0] + \"&nbsp饰&nbsp\" + StrRole[1] + \"</a>\" +\n                                        \"</div>\" +\n                                    \"</li>\" +\n                                \"</ul>\" +\n                            \"</div>\"\n                        );\n                    }\n                }\n            });\n                            \n\n        }\n\n        //写评论\n        function writeComment(){\n            layui.use(['laypage', 'layer', 'table'], function(){\n                var laypage = layui.laypage;\n                var layer = layui.layer;\n                var table = layui.table\n                //写评论\n                layer.open({\n                    type: 1\n                    ,title: \"编写评论\" //不显示标题栏\n                    ,closeBtn: false\n                    ,area: '430px;'\n                    ,shade: 0.8\n                    ,offset: clientHeight/20\n                    ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                    ,btn: ['确认评价', '取消']\n                    ,yes: function(){\n                        var comment_content = $('#comment_content_write').val();\n                        if(comment_content == \"\"){\n                            layer.alert('评论内容不能空，评论失败！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.close(layer.index);\n                                }\n                            );\n                        }\n                        else{\n                            if(comment_content.length > 150){\n                                layer.alert('字数超过150个，评论失败！',{icon: 0,offset: clientHeight/5},\n                                    function (){\n                                        layer.close(layer.index);\n                                    }\n                                );\n                            }else{\n                                console.log(movie_id);\n                                console.log(comment_content);\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/comment/addCommentByUser\",\n                                    dataType:'json',\n                                    data: {\n                                        movie_id: movie_id,\n                                        comment_content: comment_content\n                                    },\n                                    success:function (obj) {\n                                        if(obj.code == 0){\n                                            layer.alert('评价成功！',{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert(obj.msg,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    }\n                                });\n\n                            }\n                        }\n                    }\n                    ,btnAlign: 'c movie-last'\n                    ,moveType: 0 //拖拽模式，0或者1\n                    ,content: WriteCommentHtml\n                    // ,success: function(layero){\n                    //     $('#user_name_write').val(user_name);\n                    // }\n                });\n            });\n        }\n        //删除评论\n        function deleteConfirm(comment_id){\n            layui.use(['layer'], function(){\n                var layer = layui.layer;\n                layer.alert('确定要删除该条评论信息吗？',{icon: 0,offset: clientHeight/5}\n                    ,function () {   \n                        $.ajax({\n                            type:'post',\n                            url: url + \"/comment/deleteComemnt\",\n                            dataType:'json',\n                            data: {\n                                comment_id: comment_id,\n                            },\n                            success:function (obj) {\n                                if(obj.code == 0){\n                                    layer.alert(obj.msg,{icon: 0,offset: clientHeight/5},\n                                        function (){\n                                            layer.closeAll();\n                                            location.reload();\n                                        }\n                                    );\n                                }else{\n                                    layer.alert(obj.msg,{icon: 0,offset: clientHeight/5},\n                                        function (){\n                                            layer.closeAll();\n                                        }\n                                    );\n                                }\n                            }\n                        });\n                    }\n                );\n            });\n        }\n        //修改评论\n        function updateConfirm(comment_id,user_name,comment_content,comment_time){\n            layui.use(['laypage', 'layer', 'table'], function(){\n                var laypage = layui.laypage;\n                var layer = layui.layer;\n                var table = layui.table\n                //修改评论\n                layer.open({\n                    type: 1\n                    ,title: \"修改评论\" //不显示标题栏\n                    ,closeBtn: false\n                    ,area: '430px;'\n                    ,shade: 0.8\n                    ,offset: clientHeight/20\n                    ,id: 'LAY_layuipro' //设定一个id，防止重复弹出\n                    ,btn: ['确认修改', '取消']\n                    ,yes: function(){\n                        var comment_content = $('#comment_content').val();\n                        if(comment_content == \"\"){\n                            layer.alert('评论内容不能空，修改失败！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.close(layer.index);\n                                }\n                            );\n                        }\n                        else{\n                            console.log(comment_content.length);\n                            if(comment_content.length > 150){\n                                layer.alert('字数超过150个，评论失败！',{icon: 0,offset: clientHeight/5},\n                                function (){\n                                    layer.close(layer.index);\n                                }\n                            );\n                            }else{\n                                $.ajax({\n                                    type:'post',\n                                    url: url + \"/comment/updateComment\",\n                                    dataType:'json',\n                                    data: {\n                                        comment_id: comment_id,\n                                        comment_content: comment_content\n                                    },\n                                    success:function (obj) {\n                                        if(obj.code == 0){\n                                            layer.alert(obj.msg,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                    location.reload();\n                                                }\n                                            );\n                                        }else{\n                                            layer.alert(obj.msg,{icon: 0,offset: clientHeight/5},\n                                                function (){\n                                                    layer.closeAll();\n                                                }\n                                            );\n                                        }\n                                    },\n                                    error: function(){\n                                        alert(\"network error!\");\n                                    }\n                                });\n                            }\n                        }\n                    }\n                    ,btnAlign: 'c movie-last'\n                    ,moveType: 0 //拖拽模式，0或者1\n                    ,content: UpdateCommentHtml\n                    ,success: function(layero){\n                        $('#user_name').val(user_name);\n                        $('#comment_time').val(comment_time);\n                        $('#comment_content').val(comment_content);\n                    }\n                });\n            });\n        }\n\n        //获取url参数\n        function getUrlParams(name) { // 不传name返回所有值，否则返回对应值\n            var url = window.location.search;\n            if (url.indexOf('?') == 1) { return false; }\n            url = url.substr(1);\n            url = url.split('&');\n            var name = name || '';\n            var nameres;\n            // 获取全部参数及其值\n            for(var i=0;i<url.length;i++) {\n                var info = url[i].split('=');\n                var obj = {};\n                obj[info[0]] = decodeURI(info[1]);\n                url[i] = obj;\n            }\n            // 如果传入一个参数名称，就匹配其值\n            if (name) {\n                for(var i=0;i<url.length;i++) {\n                    for (const key in url[i]) {\n                        if (key == name) {\n                            nameres = url[i][key];\n                        }\n                    }\n                }\n            } else {\n                nameres = url;\n            }\n            // 返回结果\n            return nameres;\n        }\n    \n    </script>\n    <!-- ------------------------------------------------------------------- -->\n\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/movieList.jsp",
    "content": "﻿<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/movieList.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-电影</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 80px;\"></div>\n    \n    <!-- 副导航栏 -->\n    <ul class=\"layui-nav fu-nav\">\n            <div id=\"yui\"></div>\n        <li class=\"layui-nav-item layui-this\"><a>正在热映</a></li>\n        <li class=\"layui-nav-item\"><a>即将上映</a></li>\n        <li class=\"layui-nav-item\"><a>经典影片</a></li>\n    </ul>\n\n    <!-- 主体 -->\n    <div class=\"main\">\n        <div class=\"main-Tagsz main-inner movieList\">\n            <div class=\"movies-channel\">\n                <div class=\"tags-panel\">\n                    <ul class=\"tags-lines\">\n                        <li class=\"tags-line\">\n                            <div class=\"tags-title\">类型 :</div>\n                            <ul class=\"tags tags-type\">\n                            </ul>\n                        </li>\n                        <li class=\"tags-line tags-line-border\">\n                            <div class=\"tags-title\">区域 :</div>\n                            <ul class=\"tags tags-area\">\n                            </ul>\n                        </li>\n                        <li class=\"tags-line tags-line-border\">\n                            <div class=\"tags-title\">年代 :</div>\n                            <ul class=\"tags tags-year\">\n                            </ul>\n                        </li>\n                    </ul>\n                </div>\n            </div>\n\n            <div class=\"movies-panel\">\n                <div class=\"movies-sorter\">\n                        <div class=\"cat-sorter\">\n                            <ul>\n                                <li>\n                                    <span class=\"sort-control-group\" data-act=\"sort-click\" >\n                                        <span class=\"sort-control sort-radio sort-radio-checked\"></span>\n                                        <span class=\"sort-control-label\">按热门排序</span>\n                                    </span>\n                                </li>\n                                <li>\n                                    <span class=\"sort-control-group\" data-act=\"sort-click\" data-href=\"?sortId=2\">\n                                        <span class=\"sort-control sort-radio\"></span>\n                                        <span class=\"sort-control-label\">按时间排序</span>\n                                    </span>\n                                </li>\n                                <li>\n                                    <span class=\"sort-control-group\" data-act=\"sort-click\" data-href=\"?sortId=3\">\n                                        <span class=\"sort-control sort-radio\"></span>\n                                        <span class=\"sort-control-label\">按评价排序</span>\n                                    </span>\n                                </li>\n                            </ul>\n                        </div>  \t\n                </div>\n                \n                <div class=\"movies-list\">\n                    <ul class=\"movie-list\">\n    \n                    </ul>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var clientWidth = document.documentElement.clientWidth;\n        var date;\n        var area;\n        var year;\n        var movielist = $(\".movie-list\");\n        var order = \"热门\";\n        window.onload = function(){\n            funav(); //副导航栏\n            initHeader();\n            initParams(); //参数\n            initTags(); //标签\n            initMovieList(); //电影列表\n            initClass(); //布局\n        }\n\n        //初始化布局\n        function initClass(){\n            mainTagsz = $(\".main-Tagsz\")[0];\n\n            mainTagsz.style.cssText = \"width:1170px !important; margin: 0 0 0 \" + (clientWidth - 1170)/2 + \" !important;\";\n        }\n\n        //初始化电影列表\n        function initMovieList(){\n            if(getUrlParams(\"type\") == \"全部\" || getUrlParams(\"type\") == null){\n                $.ajax({\n                    type: \"post\",\n                    url: url + \"/movie/sortAllMovies\",\n                    data: {order: order},\n                    dataType: \"json\",\n                    success: function(obj){\n                        console.log(obj);\n                        for(var i = 0;i < obj.count; i++){\n                            movielist.append(\n                                \"<li> <div class=\\\"movie-item\\\"> <a href=\\\"./buyTickets.jsp?movie_id=\"+ obj.data[i].movie_id +\"\\\" target=\\\"_blank\\\"> <div class=\\\"movie-poster\\\"> <img src=\\\"\"+ obj.data[i].movie_picture +\"\\\"> </div> </a>\" +\n                                    \"<div class=\\\"channel-action channel-action-sale\\\"> <a>购票<a/> </div> <div class=\\\"movie-ver\\\"></div> </div>\" +\n                                    \"<div class=\\\"channel-detail movie-item-title\\\" title=\\\"\"+ obj.data[i].movie_cn_name +\"\\\">\" + \n                                        \"<a href=\\\"./movieDetail.jsp?movie_id=\"+ obj.data[i].movie_id +\"\\\" target=\\\"_blank\\\">\"+ obj.data[i].movie_cn_name +\"</a> </div>\" +\n                                    \"<div class=\\\"channel-detail channel-detail-orange\\\"> <i class=\\\"integer\\\">\"+ obj.data[i].movie_score +\"</i> </div>\" +\n                                    \"</li>\"\n                                    );\n                        }\n                    },\n                    error: function(){\n                        alert(\"network error!\");\n                    }\n                });\n            }else{\n                $.ajax({\n                    type: \"post\",\n                    url: url + \"/movie/findMoviesByType\",\n                    data: {type: type},\n                    dataType: \"json\",\n                    success:function(obj){\n                        console.log(obj);\n                        if(obj.count > 0){\n                            for(var i = 0;i < obj.count; i++){\n                                movielist.append(\n                                    \"<li> <div class=\\\"movie-item\\\"> <a href=\\\"./buyTickets.jsp?movie_id=\"+ obj.data[i].movie_id +\"\\\" target=\\\"_blank\\\"> <div class=\\\"movie-poster\\\"> <img src=\\\"\"+ obj.data[i].movie_picture +\"\\\"> </div> </a>\" +\n                                            \"<div class=\\\"channel-action channel-action-sale\\\"> <a>购票<a/> </div> <div class=\\\"movie-ver\\\"></div> </div>\" +\n                                        \"<div class=\\\"channel-detail movie-item-title\\\" title=\\\"\"+ obj.data[i].movie_cn_name +\"\\\">\" + \n                                            \"<a href=\\\"./movieDetail.jsp?movie_id=\"+ obj.data[i].movie_id +\"\\\" target=\\\"_blank\\\">\"+ obj.data[i].movie_cn_name +\"</a> </div>\" +\n                                        \"<div class=\\\"channel-detail channel-detail-orange\\\"> <i class=\\\"integer\\\">\"+ obj.data[i].movie_score +\"</i> </div>\" +\n                                        \"</li>\"\n                                );\n                            }\n                       }else{\n                           //movielist.append(\"<div style=\\\"height:320px\\\"><p style=\\\"text-align:center;padding:100px 0; font-size:24px;\\\">查无数据...</p></div>\");\n                           movielist.append(\"<div style=\\\"margin-top:40px;font-size:18px;color:#333;height:190px;\\\">抱歉，没有找到相关结果，请尝试用其他条件筛选。</div>\");\n                        }\n                    },\n                    error: function(){\n                        alert(\"network error!\");\n                    }\n                })\n            }\n            var radio = $('.sort-control-group');\n            for(var i = 0;i < radio.length;i++){\n                // var zz = radio[i].children[0];\n                // console.log(zz);\n                radio[i].index = i;\n                radio[i].onclick = function(){\n                    switch(this.index){\n                        case 0:\n                            radio[0].children[0].className =\"sort-control sort-radio sort-radio-checked\";\n                            radio[1].children[0].className =\"sort-control sort-radio\";\n                            radio[2].children[0].className =\"sort-control sort-radio\";\n                            order = \"热门\";\n                            break;\n                        case 1:\n                            radio[1].children[0].className =\"sort-control sort-radio sort-radio-checked\";\n                            radio[0].children[0].className =\"sort-control sort-radio\";\n                            radio[2].children[0].className =\"sort-control sort-radio\";\n                            order = \"时间\";\n                            break;\n                        case 2:\n                            radio[2].children[0].className =\"sort-control sort-radio sort-radio-checked\";\n                            radio[0].children[0].className =\"sort-control sort-radio\";\n                            radio[1].children[0].className =\"sort-control sort-radio\";\n                            order = \"评价\"\n                            break;\n                    }\n                    $('.movie-list').remove();\n                    $.ajax({\n                    type: \"post\",\n                    url: url + \"/movie/sortAllMovies\",\n                    data: {order: order},\n                    dataType: \"json\",\n                    success: function(obj){\n                        console.log(obj);\n                        var movieslist = $('.movies-list');\n                        movieslist.append(\"<ul class=\\\"movie-list\\\"></ul>\");\n                        var movielist = $('.movie-list');\n                        for(var i = 0;i < obj.count; i++){\n                            movielist.append(\n                                \"<li> <div class=\\\"movie-item\\\"> <a href=\\\"./buyTickets.jsp?movie_id=\"+ obj.data[i].movie_id +\"\\\" target=\\\"_blank\\\"> <div class=\\\"movie-poster\\\"> <img src=\\\"\"+ obj.data[i].movie_picture +\"\\\"> </div> </a>\" +\n                                    \"<div class=\\\"channel-action channel-action-sale\\\"> <a>购票<a/> </div> <div class=\\\"movie-ver\\\"></div> </div>\" +\n                                    \"<div class=\\\"channel-detail movie-item-title\\\" title=\\\"\"+ obj.data[i].movie_cn_name +\"\\\">\" + \n                                        \"<a href=\\\"./movieDetail.jsp?movie_id=\"+ obj.data[i].movie_id +\"\\\" target=\\\"_blank\\\">\"+ obj.data[i].movie_cn_name +\"</a> </div>\" +\n                                    \"<div class=\\\"channel-detail channel-detail-orange\\\"> <i class=\\\"integer\\\">\"+ obj.data[i].movie_score +\"</i> </div>\" +\n                                    \"</li>\"\n                            );\n                        }\n                    },\n                    error: function(){\n                        alert(\"network error!\");\n                    }\n                });\n                };\n            }\n        }\n        \n        //副导航栏响应\n        function funav(){\n            layui.use('element', function(){\n                var element = layui.element; \n                \n                //监听导航点击\n                element.on('nav(demo)', function(elem){\n                    layer.msg(elem.text());\n                });\n            });\n            var navitems = $(\".fu-nav\").find(\"li\").children(\"a\");\n            for(i = 0; i< navitems.length;i++){\n                navitems[i].onclick = function(){\n                    //按钮\n                }\n            }\n        }\n\n        //初始化标签\n        function initTags(){\n            var tagsType = $(\".tags-type\"),\n                tagsArea = $(\".tags-area\"),\n                tagsYear = $(\".tags-year\");\n            var TypeStr = [\"全部\",\"爱情\",\"喜剧\",\"动画\",\"剧情\",\"惊悚\",\"科幻\",\"动作\",\"悬疑\",\"犯罪\",\"冒险\",\"运动\",\"家庭\",\"古装\",\"其他\"],\n                AreaStr = [\"全部\",\"大陆\",\"美国\",\"韩国\",\"日本\",\"中国香港\",\"中国台湾\",\"泰国\",\"印度\",\"法国\",\"英国\",\"俄罗斯\",\"意大利\"],\n                YearStr = [\"全部\",\"2019\",\"2018\",\"2017\",\"2016\",\"2015\",\"2014\"];\n            var TypeActive = [],\n                AreaActive = [],\n                YearActive = [];\n            var urlTemp = [\"&type=\"+type,\"&area=\"+area,\"&year=\"+year];\n            TypeActive = inputTags(TypeStr, TypeActive, type);\n            AreaActive = inputTags(AreaStr, AreaActive, area);\n            YearActive = inputTags(YearStr, YearActive, year);\n            for(var i=0;i<TypeStr.length;i++){\n                urlTemp[0] = \"&type=\"+TypeStr[i];\n                tagsType.append(\n                    \"<li \" + TypeActive[i] + \">\" +\n                        \"<a href=\\\"?\"+ urlTemp[0] + urlTemp[1] + urlTemp[2] +\"\\\">\"+\n                            TypeStr[i] +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n            urlTemp = [\"&type=\"+type,\"&area=\"+area,\"&year=\"+year];\n            for(var i=0;i<AreaStr.length;i++){\n                urlTemp[1] = \"&area=\"+ AreaStr[i];\n                tagsArea.append(\n                    \"<li \" + AreaActive[i] + \">\" +\n                            \"<a href=\\\"?\"+ urlTemp[0] + urlTemp[1] + urlTemp[2] +\"\\\">\"+\n                            AreaStr[i] +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n            urlTemp = [\"&type=\"+type,\"&area=\"+area,\"&year=\"+year];\n            for(var i=0;i<YearStr.length;i++){\n                urlTemp[2] = \"&year=\"+ YearStr[i];\n                tagsYear.append(\n                    \"<li \" + YearActive[i] + \">\" +\n                        \"<a href=\\\"?\"+ urlTemp[0] + urlTemp[1] + urlTemp[2] +\"\\\">\"+\n                            YearStr[i] +\n                        \"</a>\" +\n                    \"</li>\"\n                );\n            }\n        }\n        //导入活跃标签\n        function inputTags(Str, Active, tags){\n            for(var i=0;i<Str.length;i++){\n                if(tags==0&&i==0){\n                    Active.push(\"class=\\\"active\\\"\");\n                    break;\n                }\n                if(Str[i]==tags){\n                    Active.push(\"class=\\\"active\\\"\");\n                }\n                else\n                Active.push(\" \");\n            }\n            return Active;\n        }\n        \n        //初始化url参数\n        function initParams(){\n            if(getUrlParams('type') == null){\n                type = \"0\";\n            }else{\n                type = getUrlParams('type');\n            }\n            if(getUrlParams('area') == null){\n                area = \"0\";\n            }else{\n                area = getUrlParams('area');\n            }\n            if(getUrlParams('year') == null){\n                year = \"0\";\n            }else{\n                year = getUrlParams('year');\n            }\n        }\n        //获取url参数\n        function getUrlParams(name) { // 不传name返回所有值，否则返回对应值\n            var url = window.location.search;\n            if (url.indexOf('?') == 1) { return false; }\n            url = url.substr(1);\n            url = url.split('&');\n            var name = name || '';\n            var nameres;\n            // 获取全部参数及其值\n            for(var i=0;i<url.length;i++) {\n                var info = url[i].split('=');\n                var obj = {};\n                obj[info[0]] = decodeURI(info[1]);\n                url[i] = obj;\n            }\n            // 如果传入一个参数名称，就匹配其值\n            if (name) {\n                for(var i=0;i<url.length;i++) {\n                    for (const key in url[i]) {\n                        if (key == name) {\n                            nameres = url[i][key];\n                        }\n                    }\n                }\n            } else {\n                nameres = url;\n            }\n            // 返回结果\n            return nameres;\n        }\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/pay.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/pay.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-支付</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 90px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"container\">\n        <div class=\"order-progress-bar\">\n            <div class=\"step first done\">\n                <span class=\"step-num\">1</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">选择影片场次</span>\n            </div>\n            <div class=\"step done\">\n                <span class=\"step-num\">2</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">选择座位</span>\n            </div>\n            <div class=\"step done\">\n                <span class=\"step-num\">3</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">付款</span>\n            </div>\n            <div class=\"step last\">\n                <span class=\"step-num\">4</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">影院取票观影</span>\n            </div>\n        </div>\n\n        <div class=\"count-down-wrapper\">\n            <div class=\"count-down\">\n                <p class=\"time-left\">\n                    请在<span class=\"minute\"></span>分钟<span class=\"second\"></span>秒内完成支付\n                </p>\n                <p class=\"tip\">超时订单会自动取消，如遇支付问题，请联系管理员</p>\n            </div>\n        </div>\n\n        <p class=\"warning\">\n            请仔细核对场次信息，出票后将<span class=\"attention\">无法退票和改签</span>\n        </p>\n\n        <table class=\"order-table\">\n            <thead>\n                <tr>\n                    <th>影片</th>\n                    <th>时间</th>\n                    <th>影院</th>\n                    <th>座位</th>\n                </tr>\n            </thead>\n            <tbody>\n               <!-- 信息表 -->\n            </tbody>\n        </table>\n\n        <div class=\"right\">\n            <div class=\"price-wrapper\">\n                <span>实际支付：</span>\n                <span class=\"price\"></span>\n            </div>\n            <div>\n                <div class=\"pay-btn\">确认支付</div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n        var json = localStorage.getItem(\"order\");\n        json = eval('(' + json + ')');\n        console.log(json);\n        var schedule_id = json.schedule_id;\n        var payBtn = $(\".pay-btn\");\n        window.onload = function(){\n            initHeader();\n            initPay(); //支付\n            timeDown(); //计时器\n        }\n\n        //初始化支付页面\n        function initPay(){\n            var orderTable = $(\".order-table\").find(\"tbody\");\n            var TempLength = json.TicketSeat.split(\",\");\n            console.log(TempLength);\n            var price = json.price;\n            $.ajax({\n                type:'post',\n                url: url + \"/schedule/findScheduleById\",\n                dataType:'json',\n                data: {\n                    schedule_id: schedule_id\n                },\n                success:function (obj) {\n                    orderTable.append(\n                        \"<tr>\" +\n                            \"<td class=\\\"movie-name\\\">\" + obj.data.schedule_movie.movie_cn_name + \"</td>\" +\n                            \"<td class=\\\"showtime\\\">\" + obj.data.schedule_startTime + \"</td>\" +\n                            \"<td class=\\\"cinema-name\\\">\" + obj.data.schedule_hall.hall_cinema.cinema_name + \"</td>\" +\n                            \"<td>\" +\n                                \"<span class=\\\"hall\\\">\" + obj.data.schedule_hall.hall_name + \"</span>\" +\n                                \"<div class=\\\"seats\\\">\" +\n                                    \"<div class=\\\"choiceseat\\\" style=\\\"display: block;\\\">\" +\n                                    \"</div>\" +\n                                \"</div>\" +\n                            \"</td>\" +\n                        \"<tr>\"\n                    );\n                    var choiceSeat = $(\".choiceseat\");\n                    for(var i=0;i<TempLength.length;i++){\n                        choiceSeat.append(\"<span class=\\\"border\\\" style=\\\"font-size: 15px;\\\">\" + TempLength[i] + \"</span>\");\n                    }\n                }\n            });\n\n            var choiceSeat = $(\".choiceseat\");\n            for(var i=0;i<TempLength.length;i++){\n                choiceSeat.append(\"<span class=\\\"border\\\" style=\\\"font-size: 15px;\\\">\" + TempLength[i] + \"</span>\");\n            }\n            $(\".price\").html(price);\n        }\n\n        //计时器\n        function timeDown(){\n            var timeMinute = $(\".minute\");\n            var timeSecond = $(\".second\");\n            var minute;\n            var second;\n            timeMinute.text(localStorage.minute);\n            timeSecond.text(localStorage.second);\n            setInterval(function(){\n                if(second==0 && minute==0){\n                    window.alert(\"支付时间已过，订单失效！\");\n                    localStorage.clear();\n                }\n                if((localStorage.second == \"NaN\") || (localStorage.second == 0 && localStorage.minute == 0))\n                {\n                    localStorage.minute = 14;\n                    localStorage.second = 59;\n                }\n                second = localStorage.second;\n                minute = localStorage.minute; \n                if(second==0){\n                    minute--;\n                    second = 60;\n                }\n                second--;\n                timeMinute.text(minute);\n                timeSecond.text(second);\n                localStorage.second = second;\n                localStorage.minute = minute;\n            },1000);\n        }\n\n        //购买\n        payBtn[0].onclick = function(){\n            var position = json.TicketSeat.split(\",\");\n            var price = json.price;\n            $.ajax({\n                type: \"post\",\n                url: url + \"/order/buyTickets\",\n                data: {\n                    schedule_id: schedule_id,\n                    position: position,\n                    price: price,\n                },\n                dataType: \"json\",\n                success: function(obj){\n                \tlocalStorage.removeItem(\"order\");\n                    if(obj.code == 0){\n                        layui.use(['layer'], function(){\n                            var layer = layui.layer;\n                            layer.alert('购票成功！',{icon: 0,offset: clientHeight/5},\n                                 function (){\n                                    layer.closeAll();\n                                    document.location.href = \"./payStatus.jsp\";\n                                 }\n                            );\n                        });\n                    }else{\n                        layui.use(['layer'], function(){\n                            var layer = layui.layer;\n                            layer.alert(obj.msg,{icon: 0,offset: clientHeight/5},\n                                 function (){\n                                    layer.closeAll();\n                                 }\n                            );\n                        });\n                    }\n                },\n                error: function(){\n                    alert(\"network error\");\n                }\n            });\n        }\n\n        //获取url参数\n        function getUrlParams(name) { // 不传name返回所有值，否则返回对应值\n            var url = window.location.search;\n            if (url.indexOf('?') == 1) { return false; }\n            url = url.substr(1);\n            url = url.split('&');\n            var name = name || '';\n            var nameres;\n            // 获取全部参数及其值\n            for(var i=0;i<url.length;i++) {\n                var info = url[i].split('=');\n                var obj = {};\n                obj[info[0]] = decodeURI(info[1]);\n                url[i] = obj;\n            }\n            // 如果传入一个参数名称，就匹配其值\n            if (name) {\n                for(var i=0;i<url.length;i++) {\n                    for (const key in url[i]) {\n                        if (key == name) {\n                            nameres = url[i][key];\n                        }\n                    }\n                }\n            } else {\n                nameres = url;\n            }\n            // 返回结果\n            return nameres;\n        }\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/payStatus.jsp",
    "content": "<%@page import=\"com.entity.User\"%>\n<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<%\n\tUser user = (User)request.getSession().getAttribute(\"user\");\n\tif(user == null){\n\t\tresponse.sendRedirect(\"./login.jsp\");\n\t}\n%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/paystatus.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-支付成功</title>\n</head>\n<body>\n\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 90px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"container\">\n        <div class=\"order-progress-bar\">\n            <div class=\"step first done\">\n                <span class=\"step-num\">1</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">选择影片场次</span>\n            </div>\n            <div class=\"step done\">\n                <span class=\"step-num\">2</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">选择座位</span>\n            </div>\n            <div class=\"step done\">\n                <span class=\"step-num\">3</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">付款</span>\n            </div>\n            <div class=\"step last done\">\n                <span class=\"step-num\">4</span>\n                <div class=\"bar\"></div>\n                <span class=\"step-next\">影院取票观影</span>\n            </div>\n        </div>\n        <div class=\"main-paystatus\">\n            <img src=\"../static/images/success.jpg\"/>\n            <p class=\"statustext\">已完成支付</p>\n        </div>\n        <div class=\"right\">\n            <p class=\"warning\">\n                该页面关闭后可以在<span class=\"attention\">个人订单</span>页面查看订单信息\n            </p>\n            <div>\n                <div class=\"pay-btn\" onclick=\"returnCenter()\">返回个人订单</div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 脚 -->\n    <jsp:include page=\"footer.jsp\"/>\n\n    <script>\n        var clientHeight = document.documentElement.clientHeight;\n\n        window.onload = function(){\n\t\t\t initHeader();\n        }\n        \n        function returnCenter(){\n            window.location.href = \"./center.jsp\"\n        }\n\n    </script>\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/selectSeat.jsp",
    "content": "﻿<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\n    <link href=\"../static/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/bootstrap/css/bootstrap.css\" rel=\"stylesheet\">\n    <script src=\"../static/bootstrap/js/jquery-3.3.1.min.js\"></script>\n    <script src=\"../static/bootstrap/js/bootstrap.min.js\"></script>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"../static/images/logo.ico\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/header.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/main.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/footer.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/buyTickets.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/movieDetail.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../static/css/selectSeat.css\">\n    <script src=\"../static/js/header.js\" charset=\"utf-8\"></script>\n    <script src=\"../static/js/Api.js\"></script>\n    <script src=\"../static/layui/layui.js\" charset=\"utf-8\"></script>\n    <link rel=\"stylesheet\" href=\"../static/layui/css/layui.css\" media=\"all\">\n    <title>鹰眼电影-选场次</title>\n</head>\n<body>\n    <!-- ------------------------------------------------------------------- -->\n    <!-- 导航栏 -->\n    <jsp:include page=\"header.jsp\"/>\n    \n    <!-- 占位符 -->\n    <div style=\"margin-top: 80px;\"></div>\n\n    <!-- 巨幕 -->\n    <div class=\"banner2\">\n        <div class=\"wrapper clearfix\">\n            <div class=\"cinema-left\">\n                <div class=\"avatar-shadow\">\n\n                </div>\n            </div>\n\n            <div class=\"cinema-main clearfix\">\n                <div class=\"cinema-brief-container\">\n                    <div class=\"telphone\">电话：0335-2661222</div>\n                    <div class=\"features-group\">\n                        <div class=\"group-title\">影院服务</div>\n\n                        <div class=\"feature\">\n                            <span class=\"tag \">3D眼镜</span>\n                            <p class=\"desc text-ellipsis\" title=\"免押金\">免押金</p>\n                        </div>\n                        <div class=\"feature\">\n                            <span class=\"tag \">可停车</span>\n                            <p class=\"desc text-ellipsis\" title=\"可停车\">停车场可凭电影票在影城票台领取3小时内免停权益</p>\n                        </div>\n                    </div>\n                </div>\n            </div>\n                \n        </div>\n    </div>\n\n    <!-- 占位符 -->\n    <div style=\"margin-top: 50px;\"></div>\n\n    <!-- 主体 -->\n    <div class=\"main\">\n        <div class=\"main-inner main-bodyz\">\n            <div class=\"movie-list-container\" data-cinemaid=\"8330\">\n                <!-- 电影海报 -->\n                <div class=\"movie-list\">\n                    <!--<span class=\"pointer\" style=\"left: 395px;\"></span>-->\n                </div>\n                <span class=\"scroll-prev scroll-btn\"></span>\n                <span class=\"scroll-next scroll-btn\"></span>\n            </div>\n\n            <div class=\"show-list active\" data-index=\"0\">\n                <!-- 电影信息 -->\n                <div class=\"movie-info\">\n                </div>\n                <!-- 观影时间 -->\n                <div class=\"show-date\">\n                    <span>观影时间 :</span>  \n                </div>\n                <!-- 场次列表 -->\n                <div class=\"plist-container active\">\n                    <table class=\"plist\">\n                        <thead>\n                            <tr>\n                                <th>放映时间</th>\n                                <th>语言版本</th>\n                                <th>放映厅</th>\n                                <th>售价（元）</th>\n                                <th>选座购票</th>\n                            </tr>\n                        </thead>\n                        <tbody>\n                          \n                        </tbody>\n                    </table>\n                </div>\n            </div>\n        </div>\n    </div>\n\n     <!-- 脚 -->\n     <jsp:include page=\"footer.jsp\"/>\n\n    <!-- ------------------------------------------------------------------- -->\n    <script>\n        window.onload = function(){\n            initBanner(); //初始化巨幕\n            initHeader();\n        }\n\n        //初始化巨幕\n        function initBanner(){\n            movie_id = getUrlParams('movie_id');\n            cinema_id = getUrlParams('cinema_id');\n            var cinemaBriefContainer = $(\".cinema-brief-container\");\n            var avatarShadow = $(\".avatar-shadow\");\n            $.ajax({\n                type:'post',\n                url: url + \"/schedule/findScheduleByCinemaAndMovie\",\n                dataType:'json',\n                data: {\n                    movie_id: movie_id,\n                    cinema_id: cinema_id\n                },\n                success:function (obj) {\n                    console.log(obj);\n                    cinemaBriefContainer.prepend(\n                        \"<h3 class=\\\"name text-ellipsis\\\">\" + obj.data[0].schedule_hall.hall_cinema.cinema_name + \"</h3>\" +\n                        \"<div class=\\\"address text-ellipsis\\\">\" + obj.data[0].schedule_hall.hall_cinema.cinema_address + \"</div>\"\n                    );\n                    avatarShadow.append(\n                        \"<img class=\\\"avatar\\\" src=\\\"../static/images/cinemas/\" + obj.data[0].schedule_hall.hall_cinema.cinema_name + \".jpg\\\">\" +\n                        \"<div class=\\\"avatar-num\\\">查看全部21张图片</div>\"\n                    );\n                    initMoive(obj); //初始化电影信息\n                    initSchedule(obj); //初始化场次信息\n                }\n            });\n        }\n\n        //初始化电影信息\n        function initMoive(obj){\n           // console.log(obj);\n            var Data = new Date();\n            var Month = Data.getMonth() + 1;\n            var Day = Data.getDate();\n            var movieList = $(\".movie-list\");\n            var movieInfo = $(\".movie-info\");\n            var showDate = $(\".show-date\");\n            for(var i=0;i<5;i++){\n                movieList.append(\n                    \"<div class=\\\"movie active\\\" data-index=\\\"0\\\">\" +\n                        \"<img src=\\\"../static/images/stills/\" + obj.data[0].schedule_movie.movie_cn_name + \"/\" + (i+1) + \".jpg\\\" alt=\\\"\\\">\" +\n                    \"</div>\"\n                );\n            }\n         \n            movieInfo.append(\n                \"<div>\" +\n                    \"<h3 class=\\\"movie-name\\\">\"+ obj.data[0].schedule_movie.movie_cn_name +\"</h3>\" +\n                    \"<span class=\\\"score sc\\\">\"+ obj.data[0].schedule_movie.movie_score +\"</span>\" +\n                \"</div>\" +\n                \"<div class=\\\"movie-desc\\\">\" +\n                    \"<div>\" +\n                        \"<span class=\\\"key\\\">时长 : </span>\" +\n                        \"<span class=\\\"value\\\">\"+ obj.data[0].schedule_movie.movie_duration +\"</span>\" +\n                    \"</div>\" +\n                    \"<div>\" +\n                        \"<span class=\\\"key\\\">类型 :</span>\" +\n                        \"<span class=\\\"value\\\">\"+ obj.data[0].schedule_movie.movie_type +\"</span>\" +\n                    \"</div>\" +\n                    \"<div>\" +\n                        \"<span class=\\\"key\\\">导演 :</span>\" +\n                        \"<span class=\\\"value\\\">\"+ obj.data[0].schedule_movie.movie_director+\"</span>\" +\n                    \"</div>\" +\n                \"</div>\"\n            )\n            showDate.append(\"<span class=\\\"date-item active\\\" data-index=\\\"${status.index}\\\">今天\" + Month + \"月\" + (Day+i) + \"</span>  \");\n        }\n\n        //初始化场次信息\n        function initSchedule(obj){\n            var plist = $(\".plist\").find(\"tbody\");\n\n            for(var i = 0;i < obj.data.length;i++){\n                plist.append(\n                    \"<tr class=\\\"\\\">\" +\n                        \"<td> <span class=\\\"begin-time\\\">\"+ obj.data[i].schedule_startTime +\"</span> <br> </td>\" +\n                        \"<td> <span class=\\\"lang\\\">\" + obj.data[i].schedule_movie.movie_country +\"</span> </td>\" +\n                        \"<td> <span class=\\\"hall\\\">\" + obj.data[i].schedule_hall.hall_name + \"</span> </td>\" +\n                        \"<td> <span class=\\\"sell-price\\\"> <span class=\\\"stonefont\\\">\" + obj.data[i].schedule_price + \"</span> </span> </td>\" +\n                        \"<td> <a href=\\\"./buySeat.jsp?schedule_id=\"+ obj.data[i].schedule_id +\"\\\" class=\\\"buy-btn normal\\\">选座购票</a> </td>\" +\n                    \"</tr>\"   \n                            );\n            }\n        }\n                    \n        //获取url参数\n        function getUrlParams(name) { // 不传name返回所有值，否则返回对应值\n            var url = window.location.search;\n            if (url.indexOf('?') == 1) { return false; }\n            url = url.substr(1);\n            url = url.split('&');\n            var name = name || '';\n            var nameres;\n            // 获取全部参数及其值\n            for(var i=0;i<url.length;i++) {\n                var info = url[i].split('=');\n                var obj = {};\n                obj[info[0]] = decodeURI(info[1]);\n                url[i] = obj;\n            }\n            // 如果传入一个参数名称，就匹配其值\n            if (name) {\n                for(var i=0;i<url.length;i++) {\n                    for (const key in url[i]) {\n                        if (key == name) {\n                            nameres = url[i][key];\n                        }\n                    }\n                }\n            } else {\n                nameres = url;\n            }\n            // 返回结果\n            return nameres;\n        }\n\n    </script>\n    <!-- ------------------------------------------------------------------- -->\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/jsp/test.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<script src=\"../static/js/jquery-3.3.1.min.js\"></script>\n<title>文件上传</title>\n</head>\n<style>\n    *{\n        margin: 0;\n        padding: 0;\n    }\n    .upload{\n        width:500px;\n        height: 700px;\n        margin: 50px auto;\n    }\n    .upload #file{\n        height: auto;\n        padding: 20px;\n    }\n</style>\n<body>\n \t<form class=\"upload\" id=\"uploadform\">\n        <label>昵称</label>\n        <input type=\"text\" name=\"user_name\" id=\"user_name\">\n        <!-- <label>选择文件</label> -->\n        <input type=\"file\" id=\"file\" name=\"file\">\n        <input type=\"button\" id=\"submit\" value=\"formdata提交\">\n        <!-- test img显示 路径 upload/head -->\n    </form>\n    <img src=\"../upload/movies/demo.jpg\" alt=\"this is a zimg\"/>\n \t<script>\n       $('#submit').click(function(){\n           var formData = new FormData();\n           var user_name = $('#user_name').val();\n           var file = $('#file')[0].files[0];\n           //console.log(file.name);\n           if(file != \"\"){\n               formData.append(\"file\",file);\n           }\n           formData.append(\"user_name\",user_name);\n          // console.log(user_name);\n           //console.log(formData);\n         //  console.log(formData.get(\"user_name\"));\n           $.ajax({\n                type: \"post\",\n                url: \"http://localhost:8080/user/test\",\n                data: formData,\n                processData: false,\n                contentType: false,\n                success: function(result){\n                    console.log(result);\n                    var obj = eval('(' + result + ')');\n                    console.log(obj.file);\n                }\n           });\n       })\n    </script>\n</body>\n</html>"
  },
  {
    "path": "src/main/webapp/static/bootstrap/bootstrap.js",
    "content": "/*!\n  * Bootstrap v4.1.3 (https://getbootstrap.com/)\n  * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n  */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery'), require('popper.js')) :\n  typeof define === 'function' && define.amd ? define(['exports', 'jquery', 'popper.js'], factory) :\n  (factory((global.bootstrap = {}),global.jQuery,global.Popper));\n}(this, (function (exports,$,Popper) { 'use strict';\n\n  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;\n  Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper;\n\n  function _defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      Object.defineProperty(target, descriptor.key, descriptor);\n    }\n  }\n\n  function _createClass(Constructor, protoProps, staticProps) {\n    if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) _defineProperties(Constructor, staticProps);\n    return Constructor;\n  }\n\n  function _defineProperty(obj, key, value) {\n    if (key in obj) {\n      Object.defineProperty(obj, key, {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    } else {\n      obj[key] = value;\n    }\n\n    return obj;\n  }\n\n  function _objectSpread(target) {\n    for (var i = 1; i < arguments.length; i++) {\n      var source = arguments[i] != null ? arguments[i] : {};\n      var ownKeys = Object.keys(source);\n\n      if (typeof Object.getOwnPropertySymbols === 'function') {\n        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {\n          return Object.getOwnPropertyDescriptor(source, sym).enumerable;\n        }));\n      }\n\n      ownKeys.forEach(function (key) {\n        _defineProperty(target, key, source[key]);\n      });\n    }\n\n    return target;\n  }\n\n  function _inheritsLoose(subClass, superClass) {\n    subClass.prototype = Object.create(superClass.prototype);\n    subClass.prototype.constructor = subClass;\n    subClass.__proto__ = superClass;\n  }\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): util.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Util = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Private TransitionEnd Helpers\n     * ------------------------------------------------------------------------\n     */\n    var TRANSITION_END = 'transitionend';\n    var MAX_UID = 1000000;\n    var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)\n\n    function toType(obj) {\n      return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase();\n    }\n\n    function getSpecialTransitionEndEvent() {\n      return {\n        bindType: TRANSITION_END,\n        delegateType: TRANSITION_END,\n        handle: function handle(event) {\n          if ($$$1(event.target).is(this)) {\n            return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params\n          }\n\n          return undefined; // eslint-disable-line no-undefined\n        }\n      };\n    }\n\n    function transitionEndEmulator(duration) {\n      var _this = this;\n\n      var called = false;\n      $$$1(this).one(Util.TRANSITION_END, function () {\n        called = true;\n      });\n      setTimeout(function () {\n        if (!called) {\n          Util.triggerTransitionEnd(_this);\n        }\n      }, duration);\n      return this;\n    }\n\n    function setTransitionEndSupport() {\n      $$$1.fn.emulateTransitionEnd = transitionEndEmulator;\n      $$$1.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();\n    }\n    /**\n     * --------------------------------------------------------------------------\n     * Public Util Api\n     * --------------------------------------------------------------------------\n     */\n\n\n    var Util = {\n      TRANSITION_END: 'bsTransitionEnd',\n      getUID: function getUID(prefix) {\n        do {\n          // eslint-disable-next-line no-bitwise\n          prefix += ~~(Math.random() * MAX_UID); // \"~~\" acts like a faster Math.floor() here\n        } while (document.getElementById(prefix));\n\n        return prefix;\n      },\n      getSelectorFromElement: function getSelectorFromElement(element) {\n        var selector = element.getAttribute('data-target');\n\n        if (!selector || selector === '#') {\n          selector = element.getAttribute('href') || '';\n        }\n\n        try {\n          return document.querySelector(selector) ? selector : null;\n        } catch (err) {\n          return null;\n        }\n      },\n      getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {\n        if (!element) {\n          return 0;\n        } // Get transition-duration of the element\n\n\n        var transitionDuration = $$$1(element).css('transition-duration');\n        var floatTransitionDuration = parseFloat(transitionDuration); // Return 0 if element or transition duration is not found\n\n        if (!floatTransitionDuration) {\n          return 0;\n        } // If multiple durations are defined, take the first\n\n\n        transitionDuration = transitionDuration.split(',')[0];\n        return parseFloat(transitionDuration) * MILLISECONDS_MULTIPLIER;\n      },\n      reflow: function reflow(element) {\n        return element.offsetHeight;\n      },\n      triggerTransitionEnd: function triggerTransitionEnd(element) {\n        $$$1(element).trigger(TRANSITION_END);\n      },\n      // TODO: Remove in v5\n      supportsTransitionEnd: function supportsTransitionEnd() {\n        return Boolean(TRANSITION_END);\n      },\n      isElement: function isElement(obj) {\n        return (obj[0] || obj).nodeType;\n      },\n      typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {\n        for (var property in configTypes) {\n          if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n            var expectedTypes = configTypes[property];\n            var value = config[property];\n            var valueType = value && Util.isElement(value) ? 'element' : toType(value);\n\n            if (!new RegExp(expectedTypes).test(valueType)) {\n              throw new Error(componentName.toUpperCase() + \": \" + (\"Option \\\"\" + property + \"\\\" provided type \\\"\" + valueType + \"\\\" \") + (\"but expected type \\\"\" + expectedTypes + \"\\\".\"));\n            }\n          }\n        }\n      }\n    };\n    setTransitionEndSupport();\n    return Util;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): alert.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Alert = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'alert';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.alert';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var Selector = {\n      DISMISS: '[data-dismiss=\"alert\"]'\n    };\n    var Event = {\n      CLOSE: \"close\" + EVENT_KEY,\n      CLOSED: \"closed\" + EVENT_KEY,\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      ALERT: 'alert',\n      FADE: 'fade',\n      SHOW: 'show'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Alert =\n    /*#__PURE__*/\n    function () {\n      function Alert(element) {\n        this._element = element;\n      } // Getters\n\n\n      var _proto = Alert.prototype;\n\n      // Public\n      _proto.close = function close(element) {\n        var rootElement = this._element;\n\n        if (element) {\n          rootElement = this._getRootElement(element);\n        }\n\n        var customEvent = this._triggerCloseEvent(rootElement);\n\n        if (customEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        this._removeElement(rootElement);\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        this._element = null;\n      }; // Private\n\n\n      _proto._getRootElement = function _getRootElement(element) {\n        var selector = Util.getSelectorFromElement(element);\n        var parent = false;\n\n        if (selector) {\n          parent = document.querySelector(selector);\n        }\n\n        if (!parent) {\n          parent = $$$1(element).closest(\".\" + ClassName.ALERT)[0];\n        }\n\n        return parent;\n      };\n\n      _proto._triggerCloseEvent = function _triggerCloseEvent(element) {\n        var closeEvent = $$$1.Event(Event.CLOSE);\n        $$$1(element).trigger(closeEvent);\n        return closeEvent;\n      };\n\n      _proto._removeElement = function _removeElement(element) {\n        var _this = this;\n\n        $$$1(element).removeClass(ClassName.SHOW);\n\n        if (!$$$1(element).hasClass(ClassName.FADE)) {\n          this._destroyElement(element);\n\n          return;\n        }\n\n        var transitionDuration = Util.getTransitionDurationFromElement(element);\n        $$$1(element).one(Util.TRANSITION_END, function (event) {\n          return _this._destroyElement(element, event);\n        }).emulateTransitionEnd(transitionDuration);\n      };\n\n      _proto._destroyElement = function _destroyElement(element) {\n        $$$1(element).detach().trigger(Event.CLOSED).remove();\n      }; // Static\n\n\n      Alert._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var $element = $$$1(this);\n          var data = $element.data(DATA_KEY);\n\n          if (!data) {\n            data = new Alert(this);\n            $element.data(DATA_KEY, data);\n          }\n\n          if (config === 'close') {\n            data[config](this);\n          }\n        });\n      };\n\n      Alert._handleDismiss = function _handleDismiss(alertInstance) {\n        return function (event) {\n          if (event) {\n            event.preventDefault();\n          }\n\n          alertInstance.close(this);\n        };\n      };\n\n      _createClass(Alert, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }]);\n\n      return Alert;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Alert._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Alert;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Alert._jQueryInterface;\n    };\n\n    return Alert;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): button.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Button = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'button';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.button';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var ClassName = {\n      ACTIVE: 'active',\n      BUTTON: 'btn',\n      FOCUS: 'focus'\n    };\n    var Selector = {\n      DATA_TOGGLE_CARROT: '[data-toggle^=\"button\"]',\n      DATA_TOGGLE: '[data-toggle=\"buttons\"]',\n      INPUT: 'input',\n      ACTIVE: '.active',\n      BUTTON: '.btn'\n    };\n    var Event = {\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY,\n      FOCUS_BLUR_DATA_API: \"focus\" + EVENT_KEY + DATA_API_KEY + \" \" + (\"blur\" + EVENT_KEY + DATA_API_KEY)\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Button =\n    /*#__PURE__*/\n    function () {\n      function Button(element) {\n        this._element = element;\n      } // Getters\n\n\n      var _proto = Button.prototype;\n\n      // Public\n      _proto.toggle = function toggle() {\n        var triggerChangeEvent = true;\n        var addAriaPressed = true;\n        var rootElement = $$$1(this._element).closest(Selector.DATA_TOGGLE)[0];\n\n        if (rootElement) {\n          var input = this._element.querySelector(Selector.INPUT);\n\n          if (input) {\n            if (input.type === 'radio') {\n              if (input.checked && this._element.classList.contains(ClassName.ACTIVE)) {\n                triggerChangeEvent = false;\n              } else {\n                var activeElement = rootElement.querySelector(Selector.ACTIVE);\n\n                if (activeElement) {\n                  $$$1(activeElement).removeClass(ClassName.ACTIVE);\n                }\n              }\n            }\n\n            if (triggerChangeEvent) {\n              if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {\n                return;\n              }\n\n              input.checked = !this._element.classList.contains(ClassName.ACTIVE);\n              $$$1(input).trigger('change');\n            }\n\n            input.focus();\n            addAriaPressed = false;\n          }\n        }\n\n        if (addAriaPressed) {\n          this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName.ACTIVE));\n        }\n\n        if (triggerChangeEvent) {\n          $$$1(this._element).toggleClass(ClassName.ACTIVE);\n        }\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        this._element = null;\n      }; // Static\n\n\n      Button._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          if (!data) {\n            data = new Button(this);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (config === 'toggle') {\n            data[config]();\n          }\n        });\n      };\n\n      _createClass(Button, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }]);\n\n      return Button;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {\n      event.preventDefault();\n      var button = event.target;\n\n      if (!$$$1(button).hasClass(ClassName.BUTTON)) {\n        button = $$$1(button).closest(Selector.BUTTON);\n      }\n\n      Button._jQueryInterface.call($$$1(button), 'toggle');\n    }).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {\n      var button = $$$1(event.target).closest(Selector.BUTTON)[0];\n      $$$1(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type));\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Button._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Button;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Button._jQueryInterface;\n    };\n\n    return Button;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): carousel.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Carousel = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'carousel';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.carousel';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key\n\n    var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key\n\n    var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\n    var Default = {\n      interval: 5000,\n      keyboard: true,\n      slide: false,\n      pause: 'hover',\n      wrap: true\n    };\n    var DefaultType = {\n      interval: '(number|boolean)',\n      keyboard: 'boolean',\n      slide: '(boolean|string)',\n      pause: '(string|boolean)',\n      wrap: 'boolean'\n    };\n    var Direction = {\n      NEXT: 'next',\n      PREV: 'prev',\n      LEFT: 'left',\n      RIGHT: 'right'\n    };\n    var Event = {\n      SLIDE: \"slide\" + EVENT_KEY,\n      SLID: \"slid\" + EVENT_KEY,\n      KEYDOWN: \"keydown\" + EVENT_KEY,\n      MOUSEENTER: \"mouseenter\" + EVENT_KEY,\n      MOUSELEAVE: \"mouseleave\" + EVENT_KEY,\n      TOUCHEND: \"touchend\" + EVENT_KEY,\n      LOAD_DATA_API: \"load\" + EVENT_KEY + DATA_API_KEY,\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      CAROUSEL: 'carousel',\n      ACTIVE: 'active',\n      SLIDE: 'slide',\n      RIGHT: 'carousel-item-right',\n      LEFT: 'carousel-item-left',\n      NEXT: 'carousel-item-next',\n      PREV: 'carousel-item-prev',\n      ITEM: 'carousel-item'\n    };\n    var Selector = {\n      ACTIVE: '.active',\n      ACTIVE_ITEM: '.active.carousel-item',\n      ITEM: '.carousel-item',\n      NEXT_PREV: '.carousel-item-next, .carousel-item-prev',\n      INDICATORS: '.carousel-indicators',\n      DATA_SLIDE: '[data-slide], [data-slide-to]',\n      DATA_RIDE: '[data-ride=\"carousel\"]'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Carousel =\n    /*#__PURE__*/\n    function () {\n      function Carousel(element, config) {\n        this._items = null;\n        this._interval = null;\n        this._activeElement = null;\n        this._isPaused = false;\n        this._isSliding = false;\n        this.touchTimeout = null;\n        this._config = this._getConfig(config);\n        this._element = $$$1(element)[0];\n        this._indicatorsElement = this._element.querySelector(Selector.INDICATORS);\n\n        this._addEventListeners();\n      } // Getters\n\n\n      var _proto = Carousel.prototype;\n\n      // Public\n      _proto.next = function next() {\n        if (!this._isSliding) {\n          this._slide(Direction.NEXT);\n        }\n      };\n\n      _proto.nextWhenVisible = function nextWhenVisible() {\n        // Don't call next when the page isn't visible\n        // or the carousel or its parent isn't visible\n        if (!document.hidden && $$$1(this._element).is(':visible') && $$$1(this._element).css('visibility') !== 'hidden') {\n          this.next();\n        }\n      };\n\n      _proto.prev = function prev() {\n        if (!this._isSliding) {\n          this._slide(Direction.PREV);\n        }\n      };\n\n      _proto.pause = function pause(event) {\n        if (!event) {\n          this._isPaused = true;\n        }\n\n        if (this._element.querySelector(Selector.NEXT_PREV)) {\n          Util.triggerTransitionEnd(this._element);\n          this.cycle(true);\n        }\n\n        clearInterval(this._interval);\n        this._interval = null;\n      };\n\n      _proto.cycle = function cycle(event) {\n        if (!event) {\n          this._isPaused = false;\n        }\n\n        if (this._interval) {\n          clearInterval(this._interval);\n          this._interval = null;\n        }\n\n        if (this._config.interval && !this._isPaused) {\n          this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);\n        }\n      };\n\n      _proto.to = function to(index) {\n        var _this = this;\n\n        this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM);\n\n        var activeIndex = this._getItemIndex(this._activeElement);\n\n        if (index > this._items.length - 1 || index < 0) {\n          return;\n        }\n\n        if (this._isSliding) {\n          $$$1(this._element).one(Event.SLID, function () {\n            return _this.to(index);\n          });\n          return;\n        }\n\n        if (activeIndex === index) {\n          this.pause();\n          this.cycle();\n          return;\n        }\n\n        var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;\n\n        this._slide(direction, this._items[index]);\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1(this._element).off(EVENT_KEY);\n        $$$1.removeData(this._element, DATA_KEY);\n        this._items = null;\n        this._config = null;\n        this._element = null;\n        this._interval = null;\n        this._isPaused = null;\n        this._isSliding = null;\n        this._activeElement = null;\n        this._indicatorsElement = null;\n      }; // Private\n\n\n      _proto._getConfig = function _getConfig(config) {\n        config = _objectSpread({}, Default, config);\n        Util.typeCheckConfig(NAME, config, DefaultType);\n        return config;\n      };\n\n      _proto._addEventListeners = function _addEventListeners() {\n        var _this2 = this;\n\n        if (this._config.keyboard) {\n          $$$1(this._element).on(Event.KEYDOWN, function (event) {\n            return _this2._keydown(event);\n          });\n        }\n\n        if (this._config.pause === 'hover') {\n          $$$1(this._element).on(Event.MOUSEENTER, function (event) {\n            return _this2.pause(event);\n          }).on(Event.MOUSELEAVE, function (event) {\n            return _this2.cycle(event);\n          });\n\n          if ('ontouchstart' in document.documentElement) {\n            // If it's a touch-enabled device, mouseenter/leave are fired as\n            // part of the mouse compatibility events on first tap - the carousel\n            // would stop cycling until user tapped out of it;\n            // here, we listen for touchend, explicitly pause the carousel\n            // (as if it's the second time we tap on it, mouseenter compat event\n            // is NOT fired) and after a timeout (to allow for mouse compatibility\n            // events to fire) we explicitly restart cycling\n            $$$1(this._element).on(Event.TOUCHEND, function () {\n              _this2.pause();\n\n              if (_this2.touchTimeout) {\n                clearTimeout(_this2.touchTimeout);\n              }\n\n              _this2.touchTimeout = setTimeout(function (event) {\n                return _this2.cycle(event);\n              }, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval);\n            });\n          }\n        }\n      };\n\n      _proto._keydown = function _keydown(event) {\n        if (/input|textarea/i.test(event.target.tagName)) {\n          return;\n        }\n\n        switch (event.which) {\n          case ARROW_LEFT_KEYCODE:\n            event.preventDefault();\n            this.prev();\n            break;\n\n          case ARROW_RIGHT_KEYCODE:\n            event.preventDefault();\n            this.next();\n            break;\n\n          default:\n        }\n      };\n\n      _proto._getItemIndex = function _getItemIndex(element) {\n        this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM)) : [];\n        return this._items.indexOf(element);\n      };\n\n      _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {\n        var isNextDirection = direction === Direction.NEXT;\n        var isPrevDirection = direction === Direction.PREV;\n\n        var activeIndex = this._getItemIndex(activeElement);\n\n        var lastItemIndex = this._items.length - 1;\n        var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;\n\n        if (isGoingToWrap && !this._config.wrap) {\n          return activeElement;\n        }\n\n        var delta = direction === Direction.PREV ? -1 : 1;\n        var itemIndex = (activeIndex + delta) % this._items.length;\n        return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];\n      };\n\n      _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {\n        var targetIndex = this._getItemIndex(relatedTarget);\n\n        var fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM));\n\n        var slideEvent = $$$1.Event(Event.SLIDE, {\n          relatedTarget: relatedTarget,\n          direction: eventDirectionName,\n          from: fromIndex,\n          to: targetIndex\n        });\n        $$$1(this._element).trigger(slideEvent);\n        return slideEvent;\n      };\n\n      _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {\n        if (this._indicatorsElement) {\n          var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE));\n          $$$1(indicators).removeClass(ClassName.ACTIVE);\n\n          var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];\n\n          if (nextIndicator) {\n            $$$1(nextIndicator).addClass(ClassName.ACTIVE);\n          }\n        }\n      };\n\n      _proto._slide = function _slide(direction, element) {\n        var _this3 = this;\n\n        var activeElement = this._element.querySelector(Selector.ACTIVE_ITEM);\n\n        var activeElementIndex = this._getItemIndex(activeElement);\n\n        var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);\n\n        var nextElementIndex = this._getItemIndex(nextElement);\n\n        var isCycling = Boolean(this._interval);\n        var directionalClassName;\n        var orderClassName;\n        var eventDirectionName;\n\n        if (direction === Direction.NEXT) {\n          directionalClassName = ClassName.LEFT;\n          orderClassName = ClassName.NEXT;\n          eventDirectionName = Direction.LEFT;\n        } else {\n          directionalClassName = ClassName.RIGHT;\n          orderClassName = ClassName.PREV;\n          eventDirectionName = Direction.RIGHT;\n        }\n\n        if (nextElement && $$$1(nextElement).hasClass(ClassName.ACTIVE)) {\n          this._isSliding = false;\n          return;\n        }\n\n        var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);\n\n        if (slideEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        if (!activeElement || !nextElement) {\n          // Some weirdness is happening, so we bail\n          return;\n        }\n\n        this._isSliding = true;\n\n        if (isCycling) {\n          this.pause();\n        }\n\n        this._setActiveIndicatorElement(nextElement);\n\n        var slidEvent = $$$1.Event(Event.SLID, {\n          relatedTarget: nextElement,\n          direction: eventDirectionName,\n          from: activeElementIndex,\n          to: nextElementIndex\n        });\n\n        if ($$$1(this._element).hasClass(ClassName.SLIDE)) {\n          $$$1(nextElement).addClass(orderClassName);\n          Util.reflow(nextElement);\n          $$$1(activeElement).addClass(directionalClassName);\n          $$$1(nextElement).addClass(directionalClassName);\n          var transitionDuration = Util.getTransitionDurationFromElement(activeElement);\n          $$$1(activeElement).one(Util.TRANSITION_END, function () {\n            $$$1(nextElement).removeClass(directionalClassName + \" \" + orderClassName).addClass(ClassName.ACTIVE);\n            $$$1(activeElement).removeClass(ClassName.ACTIVE + \" \" + orderClassName + \" \" + directionalClassName);\n            _this3._isSliding = false;\n            setTimeout(function () {\n              return $$$1(_this3._element).trigger(slidEvent);\n            }, 0);\n          }).emulateTransitionEnd(transitionDuration);\n        } else {\n          $$$1(activeElement).removeClass(ClassName.ACTIVE);\n          $$$1(nextElement).addClass(ClassName.ACTIVE);\n          this._isSliding = false;\n          $$$1(this._element).trigger(slidEvent);\n        }\n\n        if (isCycling) {\n          this.cycle();\n        }\n      }; // Static\n\n\n      Carousel._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          var _config = _objectSpread({}, Default, $$$1(this).data());\n\n          if (typeof config === 'object') {\n            _config = _objectSpread({}, _config, config);\n          }\n\n          var action = typeof config === 'string' ? config : _config.slide;\n\n          if (!data) {\n            data = new Carousel(this, _config);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'number') {\n            data.to(config);\n          } else if (typeof action === 'string') {\n            if (typeof data[action] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + action + \"\\\"\");\n            }\n\n            data[action]();\n          } else if (_config.interval) {\n            data.pause();\n            data.cycle();\n          }\n        });\n      };\n\n      Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {\n        var selector = Util.getSelectorFromElement(this);\n\n        if (!selector) {\n          return;\n        }\n\n        var target = $$$1(selector)[0];\n\n        if (!target || !$$$1(target).hasClass(ClassName.CAROUSEL)) {\n          return;\n        }\n\n        var config = _objectSpread({}, $$$1(target).data(), $$$1(this).data());\n\n        var slideIndex = this.getAttribute('data-slide-to');\n\n        if (slideIndex) {\n          config.interval = false;\n        }\n\n        Carousel._jQueryInterface.call($$$1(target), config);\n\n        if (slideIndex) {\n          $$$1(target).data(DATA_KEY).to(slideIndex);\n        }\n\n        event.preventDefault();\n      };\n\n      _createClass(Carousel, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }]);\n\n      return Carousel;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler);\n    $$$1(window).on(Event.LOAD_DATA_API, function () {\n      var carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE));\n\n      for (var i = 0, len = carousels.length; i < len; i++) {\n        var $carousel = $$$1(carousels[i]);\n\n        Carousel._jQueryInterface.call($carousel, $carousel.data());\n      }\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Carousel._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Carousel;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Carousel._jQueryInterface;\n    };\n\n    return Carousel;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): collapse.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Collapse = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'collapse';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.collapse';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var Default = {\n      toggle: true,\n      parent: ''\n    };\n    var DefaultType = {\n      toggle: 'boolean',\n      parent: '(string|element)'\n    };\n    var Event = {\n      SHOW: \"show\" + EVENT_KEY,\n      SHOWN: \"shown\" + EVENT_KEY,\n      HIDE: \"hide\" + EVENT_KEY,\n      HIDDEN: \"hidden\" + EVENT_KEY,\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      SHOW: 'show',\n      COLLAPSE: 'collapse',\n      COLLAPSING: 'collapsing',\n      COLLAPSED: 'collapsed'\n    };\n    var Dimension = {\n      WIDTH: 'width',\n      HEIGHT: 'height'\n    };\n    var Selector = {\n      ACTIVES: '.show, .collapsing',\n      DATA_TOGGLE: '[data-toggle=\"collapse\"]'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Collapse =\n    /*#__PURE__*/\n    function () {\n      function Collapse(element, config) {\n        this._isTransitioning = false;\n        this._element = element;\n        this._config = this._getConfig(config);\n        this._triggerArray = $$$1.makeArray(document.querySelectorAll(\"[data-toggle=\\\"collapse\\\"][href=\\\"#\" + element.id + \"\\\"],\" + (\"[data-toggle=\\\"collapse\\\"][data-target=\\\"#\" + element.id + \"\\\"]\")));\n        var toggleList = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE));\n\n        for (var i = 0, len = toggleList.length; i < len; i++) {\n          var elem = toggleList[i];\n          var selector = Util.getSelectorFromElement(elem);\n          var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {\n            return foundElem === element;\n          });\n\n          if (selector !== null && filterElement.length > 0) {\n            this._selector = selector;\n\n            this._triggerArray.push(elem);\n          }\n        }\n\n        this._parent = this._config.parent ? this._getParent() : null;\n\n        if (!this._config.parent) {\n          this._addAriaAndCollapsedClass(this._element, this._triggerArray);\n        }\n\n        if (this._config.toggle) {\n          this.toggle();\n        }\n      } // Getters\n\n\n      var _proto = Collapse.prototype;\n\n      // Public\n      _proto.toggle = function toggle() {\n        if ($$$1(this._element).hasClass(ClassName.SHOW)) {\n          this.hide();\n        } else {\n          this.show();\n        }\n      };\n\n      _proto.show = function show() {\n        var _this = this;\n\n        if (this._isTransitioning || $$$1(this._element).hasClass(ClassName.SHOW)) {\n          return;\n        }\n\n        var actives;\n        var activesData;\n\n        if (this._parent) {\n          actives = [].slice.call(this._parent.querySelectorAll(Selector.ACTIVES)).filter(function (elem) {\n            return elem.getAttribute('data-parent') === _this._config.parent;\n          });\n\n          if (actives.length === 0) {\n            actives = null;\n          }\n        }\n\n        if (actives) {\n          activesData = $$$1(actives).not(this._selector).data(DATA_KEY);\n\n          if (activesData && activesData._isTransitioning) {\n            return;\n          }\n        }\n\n        var startEvent = $$$1.Event(Event.SHOW);\n        $$$1(this._element).trigger(startEvent);\n\n        if (startEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        if (actives) {\n          Collapse._jQueryInterface.call($$$1(actives).not(this._selector), 'hide');\n\n          if (!activesData) {\n            $$$1(actives).data(DATA_KEY, null);\n          }\n        }\n\n        var dimension = this._getDimension();\n\n        $$$1(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING);\n        this._element.style[dimension] = 0;\n\n        if (this._triggerArray.length) {\n          $$$1(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true);\n        }\n\n        this.setTransitioning(true);\n\n        var complete = function complete() {\n          $$$1(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW);\n          _this._element.style[dimension] = '';\n\n          _this.setTransitioning(false);\n\n          $$$1(_this._element).trigger(Event.SHOWN);\n        };\n\n        var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n        var scrollSize = \"scroll\" + capitalizedDimension;\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n        this._element.style[dimension] = this._element[scrollSize] + \"px\";\n      };\n\n      _proto.hide = function hide() {\n        var _this2 = this;\n\n        if (this._isTransitioning || !$$$1(this._element).hasClass(ClassName.SHOW)) {\n          return;\n        }\n\n        var startEvent = $$$1.Event(Event.HIDE);\n        $$$1(this._element).trigger(startEvent);\n\n        if (startEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        var dimension = this._getDimension();\n\n        this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + \"px\";\n        Util.reflow(this._element);\n        $$$1(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW);\n        var triggerArrayLength = this._triggerArray.length;\n\n        if (triggerArrayLength > 0) {\n          for (var i = 0; i < triggerArrayLength; i++) {\n            var trigger = this._triggerArray[i];\n            var selector = Util.getSelectorFromElement(trigger);\n\n            if (selector !== null) {\n              var $elem = $$$1([].slice.call(document.querySelectorAll(selector)));\n\n              if (!$elem.hasClass(ClassName.SHOW)) {\n                $$$1(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);\n              }\n            }\n          }\n        }\n\n        this.setTransitioning(true);\n\n        var complete = function complete() {\n          _this2.setTransitioning(false);\n\n          $$$1(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN);\n        };\n\n        this._element.style[dimension] = '';\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      };\n\n      _proto.setTransitioning = function setTransitioning(isTransitioning) {\n        this._isTransitioning = isTransitioning;\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        this._config = null;\n        this._parent = null;\n        this._element = null;\n        this._triggerArray = null;\n        this._isTransitioning = null;\n      }; // Private\n\n\n      _proto._getConfig = function _getConfig(config) {\n        config = _objectSpread({}, Default, config);\n        config.toggle = Boolean(config.toggle); // Coerce string values\n\n        Util.typeCheckConfig(NAME, config, DefaultType);\n        return config;\n      };\n\n      _proto._getDimension = function _getDimension() {\n        var hasWidth = $$$1(this._element).hasClass(Dimension.WIDTH);\n        return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;\n      };\n\n      _proto._getParent = function _getParent() {\n        var _this3 = this;\n\n        var parent = null;\n\n        if (Util.isElement(this._config.parent)) {\n          parent = this._config.parent; // It's a jQuery object\n\n          if (typeof this._config.parent.jquery !== 'undefined') {\n            parent = this._config.parent[0];\n          }\n        } else {\n          parent = document.querySelector(this._config.parent);\n        }\n\n        var selector = \"[data-toggle=\\\"collapse\\\"][data-parent=\\\"\" + this._config.parent + \"\\\"]\";\n        var children = [].slice.call(parent.querySelectorAll(selector));\n        $$$1(children).each(function (i, element) {\n          _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);\n        });\n        return parent;\n      };\n\n      _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {\n        if (element) {\n          var isOpen = $$$1(element).hasClass(ClassName.SHOW);\n\n          if (triggerArray.length) {\n            $$$1(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);\n          }\n        }\n      }; // Static\n\n\n      Collapse._getTargetFromElement = function _getTargetFromElement(element) {\n        var selector = Util.getSelectorFromElement(element);\n        return selector ? document.querySelector(selector) : null;\n      };\n\n      Collapse._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var $this = $$$1(this);\n          var data = $this.data(DATA_KEY);\n\n          var _config = _objectSpread({}, Default, $this.data(), typeof config === 'object' && config ? config : {});\n\n          if (!data && _config.toggle && /show|hide/.test(config)) {\n            _config.toggle = false;\n          }\n\n          if (!data) {\n            data = new Collapse(this, _config);\n            $this.data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config]();\n          }\n        });\n      };\n\n      _createClass(Collapse, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }]);\n\n      return Collapse;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {\n      // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n      if (event.currentTarget.tagName === 'A') {\n        event.preventDefault();\n      }\n\n      var $trigger = $$$1(this);\n      var selector = Util.getSelectorFromElement(this);\n      var selectors = [].slice.call(document.querySelectorAll(selector));\n      $$$1(selectors).each(function () {\n        var $target = $$$1(this);\n        var data = $target.data(DATA_KEY);\n        var config = data ? 'toggle' : $trigger.data();\n\n        Collapse._jQueryInterface.call($target, config);\n      });\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Collapse._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Collapse;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Collapse._jQueryInterface;\n    };\n\n    return Collapse;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): dropdown.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Dropdown = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'dropdown';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.dropdown';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n    var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key\n\n    var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key\n\n    var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key\n\n    var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key\n\n    var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)\n\n    var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + \"|\" + ARROW_DOWN_KEYCODE + \"|\" + ESCAPE_KEYCODE);\n    var Event = {\n      HIDE: \"hide\" + EVENT_KEY,\n      HIDDEN: \"hidden\" + EVENT_KEY,\n      SHOW: \"show\" + EVENT_KEY,\n      SHOWN: \"shown\" + EVENT_KEY,\n      CLICK: \"click\" + EVENT_KEY,\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY,\n      KEYDOWN_DATA_API: \"keydown\" + EVENT_KEY + DATA_API_KEY,\n      KEYUP_DATA_API: \"keyup\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      DISABLED: 'disabled',\n      SHOW: 'show',\n      DROPUP: 'dropup',\n      DROPRIGHT: 'dropright',\n      DROPLEFT: 'dropleft',\n      MENURIGHT: 'dropdown-menu-right',\n      MENULEFT: 'dropdown-menu-left',\n      POSITION_STATIC: 'position-static'\n    };\n    var Selector = {\n      DATA_TOGGLE: '[data-toggle=\"dropdown\"]',\n      FORM_CHILD: '.dropdown form',\n      MENU: '.dropdown-menu',\n      NAVBAR_NAV: '.navbar-nav',\n      VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n    };\n    var AttachmentMap = {\n      TOP: 'top-start',\n      TOPEND: 'top-end',\n      BOTTOM: 'bottom-start',\n      BOTTOMEND: 'bottom-end',\n      RIGHT: 'right-start',\n      RIGHTEND: 'right-end',\n      LEFT: 'left-start',\n      LEFTEND: 'left-end'\n    };\n    var Default = {\n      offset: 0,\n      flip: true,\n      boundary: 'scrollParent',\n      reference: 'toggle',\n      display: 'dynamic'\n    };\n    var DefaultType = {\n      offset: '(number|string|function)',\n      flip: 'boolean',\n      boundary: '(string|element)',\n      reference: '(string|element)',\n      display: 'string'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Dropdown =\n    /*#__PURE__*/\n    function () {\n      function Dropdown(element, config) {\n        this._element = element;\n        this._popper = null;\n        this._config = this._getConfig(config);\n        this._menu = this._getMenuElement();\n        this._inNavbar = this._detectNavbar();\n\n        this._addEventListeners();\n      } // Getters\n\n\n      var _proto = Dropdown.prototype;\n\n      // Public\n      _proto.toggle = function toggle() {\n        if (this._element.disabled || $$$1(this._element).hasClass(ClassName.DISABLED)) {\n          return;\n        }\n\n        var parent = Dropdown._getParentFromElement(this._element);\n\n        var isActive = $$$1(this._menu).hasClass(ClassName.SHOW);\n\n        Dropdown._clearMenus();\n\n        if (isActive) {\n          return;\n        }\n\n        var relatedTarget = {\n          relatedTarget: this._element\n        };\n        var showEvent = $$$1.Event(Event.SHOW, relatedTarget);\n        $$$1(parent).trigger(showEvent);\n\n        if (showEvent.isDefaultPrevented()) {\n          return;\n        } // Disable totally Popper.js for Dropdown in Navbar\n\n\n        if (!this._inNavbar) {\n          /**\n           * Check for Popper dependency\n           * Popper - https://popper.js.org\n           */\n          if (typeof Popper === 'undefined') {\n            throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)');\n          }\n\n          var referenceElement = this._element;\n\n          if (this._config.reference === 'parent') {\n            referenceElement = parent;\n          } else if (Util.isElement(this._config.reference)) {\n            referenceElement = this._config.reference; // Check if it's jQuery element\n\n            if (typeof this._config.reference.jquery !== 'undefined') {\n              referenceElement = this._config.reference[0];\n            }\n          } // If boundary is not `scrollParent`, then set position to `static`\n          // to allow the menu to \"escape\" the scroll parent's boundaries\n          // https://github.com/twbs/bootstrap/issues/24251\n\n\n          if (this._config.boundary !== 'scrollParent') {\n            $$$1(parent).addClass(ClassName.POSITION_STATIC);\n          }\n\n          this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());\n        } // If this is a touch-enabled device we add extra\n        // empty mouseover listeners to the body's immediate children;\n        // only needed because of broken event delegation on iOS\n        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n\n        if ('ontouchstart' in document.documentElement && $$$1(parent).closest(Selector.NAVBAR_NAV).length === 0) {\n          $$$1(document.body).children().on('mouseover', null, $$$1.noop);\n        }\n\n        this._element.focus();\n\n        this._element.setAttribute('aria-expanded', true);\n\n        $$$1(this._menu).toggleClass(ClassName.SHOW);\n        $$$1(parent).toggleClass(ClassName.SHOW).trigger($$$1.Event(Event.SHOWN, relatedTarget));\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        $$$1(this._element).off(EVENT_KEY);\n        this._element = null;\n        this._menu = null;\n\n        if (this._popper !== null) {\n          this._popper.destroy();\n\n          this._popper = null;\n        }\n      };\n\n      _proto.update = function update() {\n        this._inNavbar = this._detectNavbar();\n\n        if (this._popper !== null) {\n          this._popper.scheduleUpdate();\n        }\n      }; // Private\n\n\n      _proto._addEventListeners = function _addEventListeners() {\n        var _this = this;\n\n        $$$1(this._element).on(Event.CLICK, function (event) {\n          event.preventDefault();\n          event.stopPropagation();\n\n          _this.toggle();\n        });\n      };\n\n      _proto._getConfig = function _getConfig(config) {\n        config = _objectSpread({}, this.constructor.Default, $$$1(this._element).data(), config);\n        Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);\n        return config;\n      };\n\n      _proto._getMenuElement = function _getMenuElement() {\n        if (!this._menu) {\n          var parent = Dropdown._getParentFromElement(this._element);\n\n          if (parent) {\n            this._menu = parent.querySelector(Selector.MENU);\n          }\n        }\n\n        return this._menu;\n      };\n\n      _proto._getPlacement = function _getPlacement() {\n        var $parentDropdown = $$$1(this._element.parentNode);\n        var placement = AttachmentMap.BOTTOM; // Handle dropup\n\n        if ($parentDropdown.hasClass(ClassName.DROPUP)) {\n          placement = AttachmentMap.TOP;\n\n          if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) {\n            placement = AttachmentMap.TOPEND;\n          }\n        } else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) {\n          placement = AttachmentMap.RIGHT;\n        } else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) {\n          placement = AttachmentMap.LEFT;\n        } else if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) {\n          placement = AttachmentMap.BOTTOMEND;\n        }\n\n        return placement;\n      };\n\n      _proto._detectNavbar = function _detectNavbar() {\n        return $$$1(this._element).closest('.navbar').length > 0;\n      };\n\n      _proto._getPopperConfig = function _getPopperConfig() {\n        var _this2 = this;\n\n        var offsetConf = {};\n\n        if (typeof this._config.offset === 'function') {\n          offsetConf.fn = function (data) {\n            data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets) || {});\n            return data;\n          };\n        } else {\n          offsetConf.offset = this._config.offset;\n        }\n\n        var popperConfig = {\n          placement: this._getPlacement(),\n          modifiers: {\n            offset: offsetConf,\n            flip: {\n              enabled: this._config.flip\n            },\n            preventOverflow: {\n              boundariesElement: this._config.boundary\n            }\n          } // Disable Popper.js if we have a static display\n\n        };\n\n        if (this._config.display === 'static') {\n          popperConfig.modifiers.applyStyle = {\n            enabled: false\n          };\n        }\n\n        return popperConfig;\n      }; // Static\n\n\n      Dropdown._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          var _config = typeof config === 'object' ? config : null;\n\n          if (!data) {\n            data = new Dropdown(this, _config);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config]();\n          }\n        });\n      };\n\n      Dropdown._clearMenus = function _clearMenus(event) {\n        if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {\n          return;\n        }\n\n        var toggles = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE));\n\n        for (var i = 0, len = toggles.length; i < len; i++) {\n          var parent = Dropdown._getParentFromElement(toggles[i]);\n\n          var context = $$$1(toggles[i]).data(DATA_KEY);\n          var relatedTarget = {\n            relatedTarget: toggles[i]\n          };\n\n          if (event && event.type === 'click') {\n            relatedTarget.clickEvent = event;\n          }\n\n          if (!context) {\n            continue;\n          }\n\n          var dropdownMenu = context._menu;\n\n          if (!$$$1(parent).hasClass(ClassName.SHOW)) {\n            continue;\n          }\n\n          if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $$$1.contains(parent, event.target)) {\n            continue;\n          }\n\n          var hideEvent = $$$1.Event(Event.HIDE, relatedTarget);\n          $$$1(parent).trigger(hideEvent);\n\n          if (hideEvent.isDefaultPrevented()) {\n            continue;\n          } // If this is a touch-enabled device we remove the extra\n          // empty mouseover listeners we added for iOS support\n\n\n          if ('ontouchstart' in document.documentElement) {\n            $$$1(document.body).children().off('mouseover', null, $$$1.noop);\n          }\n\n          toggles[i].setAttribute('aria-expanded', 'false');\n          $$$1(dropdownMenu).removeClass(ClassName.SHOW);\n          $$$1(parent).removeClass(ClassName.SHOW).trigger($$$1.Event(Event.HIDDEN, relatedTarget));\n        }\n      };\n\n      Dropdown._getParentFromElement = function _getParentFromElement(element) {\n        var parent;\n        var selector = Util.getSelectorFromElement(element);\n\n        if (selector) {\n          parent = document.querySelector(selector);\n        }\n\n        return parent || element.parentNode;\n      }; // eslint-disable-next-line complexity\n\n\n      Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {\n        // If not input/textarea:\n        //  - And not a key in REGEXP_KEYDOWN => not a dropdown command\n        // If input/textarea:\n        //  - If space key => not a dropdown command\n        //  - If key is other than escape\n        //    - If key is not up or down => not a dropdown command\n        //    - If trigger inside the menu => not a dropdown command\n        if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $$$1(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {\n          return;\n        }\n\n        event.preventDefault();\n        event.stopPropagation();\n\n        if (this.disabled || $$$1(this).hasClass(ClassName.DISABLED)) {\n          return;\n        }\n\n        var parent = Dropdown._getParentFromElement(this);\n\n        var isActive = $$$1(parent).hasClass(ClassName.SHOW);\n\n        if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {\n          if (event.which === ESCAPE_KEYCODE) {\n            var toggle = parent.querySelector(Selector.DATA_TOGGLE);\n            $$$1(toggle).trigger('focus');\n          }\n\n          $$$1(this).trigger('click');\n          return;\n        }\n\n        var items = [].slice.call(parent.querySelectorAll(Selector.VISIBLE_ITEMS));\n\n        if (items.length === 0) {\n          return;\n        }\n\n        var index = items.indexOf(event.target);\n\n        if (event.which === ARROW_UP_KEYCODE && index > 0) {\n          // Up\n          index--;\n        }\n\n        if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {\n          // Down\n          index++;\n        }\n\n        if (index < 0) {\n          index = 0;\n        }\n\n        items[index].focus();\n      };\n\n      _createClass(Dropdown, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }, {\n        key: \"DefaultType\",\n        get: function get() {\n          return DefaultType;\n        }\n      }]);\n\n      return Dropdown;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + \" \" + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {\n      event.preventDefault();\n      event.stopPropagation();\n\n      Dropdown._jQueryInterface.call($$$1(this), 'toggle');\n    }).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {\n      e.stopPropagation();\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Dropdown._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Dropdown;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Dropdown._jQueryInterface;\n    };\n\n    return Dropdown;\n  }($, Popper);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): modal.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Modal = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'modal';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.modal';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n    var Default = {\n      backdrop: true,\n      keyboard: true,\n      focus: true,\n      show: true\n    };\n    var DefaultType = {\n      backdrop: '(boolean|string)',\n      keyboard: 'boolean',\n      focus: 'boolean',\n      show: 'boolean'\n    };\n    var Event = {\n      HIDE: \"hide\" + EVENT_KEY,\n      HIDDEN: \"hidden\" + EVENT_KEY,\n      SHOW: \"show\" + EVENT_KEY,\n      SHOWN: \"shown\" + EVENT_KEY,\n      FOCUSIN: \"focusin\" + EVENT_KEY,\n      RESIZE: \"resize\" + EVENT_KEY,\n      CLICK_DISMISS: \"click.dismiss\" + EVENT_KEY,\n      KEYDOWN_DISMISS: \"keydown.dismiss\" + EVENT_KEY,\n      MOUSEUP_DISMISS: \"mouseup.dismiss\" + EVENT_KEY,\n      MOUSEDOWN_DISMISS: \"mousedown.dismiss\" + EVENT_KEY,\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      SCROLLBAR_MEASURER: 'modal-scrollbar-measure',\n      BACKDROP: 'modal-backdrop',\n      OPEN: 'modal-open',\n      FADE: 'fade',\n      SHOW: 'show'\n    };\n    var Selector = {\n      DIALOG: '.modal-dialog',\n      DATA_TOGGLE: '[data-toggle=\"modal\"]',\n      DATA_DISMISS: '[data-dismiss=\"modal\"]',\n      FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',\n      STICKY_CONTENT: '.sticky-top'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Modal =\n    /*#__PURE__*/\n    function () {\n      function Modal(element, config) {\n        this._config = this._getConfig(config);\n        this._element = element;\n        this._dialog = element.querySelector(Selector.DIALOG);\n        this._backdrop = null;\n        this._isShown = false;\n        this._isBodyOverflowing = false;\n        this._ignoreBackdropClick = false;\n        this._scrollbarWidth = 0;\n      } // Getters\n\n\n      var _proto = Modal.prototype;\n\n      // Public\n      _proto.toggle = function toggle(relatedTarget) {\n        return this._isShown ? this.hide() : this.show(relatedTarget);\n      };\n\n      _proto.show = function show(relatedTarget) {\n        var _this = this;\n\n        if (this._isTransitioning || this._isShown) {\n          return;\n        }\n\n        if ($$$1(this._element).hasClass(ClassName.FADE)) {\n          this._isTransitioning = true;\n        }\n\n        var showEvent = $$$1.Event(Event.SHOW, {\n          relatedTarget: relatedTarget\n        });\n        $$$1(this._element).trigger(showEvent);\n\n        if (this._isShown || showEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        this._isShown = true;\n\n        this._checkScrollbar();\n\n        this._setScrollbar();\n\n        this._adjustDialog();\n\n        $$$1(document.body).addClass(ClassName.OPEN);\n\n        this._setEscapeEvent();\n\n        this._setResizeEvent();\n\n        $$$1(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) {\n          return _this.hide(event);\n        });\n        $$$1(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () {\n          $$$1(_this._element).one(Event.MOUSEUP_DISMISS, function (event) {\n            if ($$$1(event.target).is(_this._element)) {\n              _this._ignoreBackdropClick = true;\n            }\n          });\n        });\n\n        this._showBackdrop(function () {\n          return _this._showElement(relatedTarget);\n        });\n      };\n\n      _proto.hide = function hide(event) {\n        var _this2 = this;\n\n        if (event) {\n          event.preventDefault();\n        }\n\n        if (this._isTransitioning || !this._isShown) {\n          return;\n        }\n\n        var hideEvent = $$$1.Event(Event.HIDE);\n        $$$1(this._element).trigger(hideEvent);\n\n        if (!this._isShown || hideEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        this._isShown = false;\n        var transition = $$$1(this._element).hasClass(ClassName.FADE);\n\n        if (transition) {\n          this._isTransitioning = true;\n        }\n\n        this._setEscapeEvent();\n\n        this._setResizeEvent();\n\n        $$$1(document).off(Event.FOCUSIN);\n        $$$1(this._element).removeClass(ClassName.SHOW);\n        $$$1(this._element).off(Event.CLICK_DISMISS);\n        $$$1(this._dialog).off(Event.MOUSEDOWN_DISMISS);\n\n        if (transition) {\n          var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n          $$$1(this._element).one(Util.TRANSITION_END, function (event) {\n            return _this2._hideModal(event);\n          }).emulateTransitionEnd(transitionDuration);\n        } else {\n          this._hideModal();\n        }\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        $$$1(window, document, this._element, this._backdrop).off(EVENT_KEY);\n        this._config = null;\n        this._element = null;\n        this._dialog = null;\n        this._backdrop = null;\n        this._isShown = null;\n        this._isBodyOverflowing = null;\n        this._ignoreBackdropClick = null;\n        this._scrollbarWidth = null;\n      };\n\n      _proto.handleUpdate = function handleUpdate() {\n        this._adjustDialog();\n      }; // Private\n\n\n      _proto._getConfig = function _getConfig(config) {\n        config = _objectSpread({}, Default, config);\n        Util.typeCheckConfig(NAME, config, DefaultType);\n        return config;\n      };\n\n      _proto._showElement = function _showElement(relatedTarget) {\n        var _this3 = this;\n\n        var transition = $$$1(this._element).hasClass(ClassName.FADE);\n\n        if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n          // Don't move modal's DOM position\n          document.body.appendChild(this._element);\n        }\n\n        this._element.style.display = 'block';\n\n        this._element.removeAttribute('aria-hidden');\n\n        this._element.scrollTop = 0;\n\n        if (transition) {\n          Util.reflow(this._element);\n        }\n\n        $$$1(this._element).addClass(ClassName.SHOW);\n\n        if (this._config.focus) {\n          this._enforceFocus();\n        }\n\n        var shownEvent = $$$1.Event(Event.SHOWN, {\n          relatedTarget: relatedTarget\n        });\n\n        var transitionComplete = function transitionComplete() {\n          if (_this3._config.focus) {\n            _this3._element.focus();\n          }\n\n          _this3._isTransitioning = false;\n          $$$1(_this3._element).trigger(shownEvent);\n        };\n\n        if (transition) {\n          var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n          $$$1(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);\n        } else {\n          transitionComplete();\n        }\n      };\n\n      _proto._enforceFocus = function _enforceFocus() {\n        var _this4 = this;\n\n        $$$1(document).off(Event.FOCUSIN) // Guard against infinite focus loop\n        .on(Event.FOCUSIN, function (event) {\n          if (document !== event.target && _this4._element !== event.target && $$$1(_this4._element).has(event.target).length === 0) {\n            _this4._element.focus();\n          }\n        });\n      };\n\n      _proto._setEscapeEvent = function _setEscapeEvent() {\n        var _this5 = this;\n\n        if (this._isShown && this._config.keyboard) {\n          $$$1(this._element).on(Event.KEYDOWN_DISMISS, function (event) {\n            if (event.which === ESCAPE_KEYCODE) {\n              event.preventDefault();\n\n              _this5.hide();\n            }\n          });\n        } else if (!this._isShown) {\n          $$$1(this._element).off(Event.KEYDOWN_DISMISS);\n        }\n      };\n\n      _proto._setResizeEvent = function _setResizeEvent() {\n        var _this6 = this;\n\n        if (this._isShown) {\n          $$$1(window).on(Event.RESIZE, function (event) {\n            return _this6.handleUpdate(event);\n          });\n        } else {\n          $$$1(window).off(Event.RESIZE);\n        }\n      };\n\n      _proto._hideModal = function _hideModal() {\n        var _this7 = this;\n\n        this._element.style.display = 'none';\n\n        this._element.setAttribute('aria-hidden', true);\n\n        this._isTransitioning = false;\n\n        this._showBackdrop(function () {\n          $$$1(document.body).removeClass(ClassName.OPEN);\n\n          _this7._resetAdjustments();\n\n          _this7._resetScrollbar();\n\n          $$$1(_this7._element).trigger(Event.HIDDEN);\n        });\n      };\n\n      _proto._removeBackdrop = function _removeBackdrop() {\n        if (this._backdrop) {\n          $$$1(this._backdrop).remove();\n          this._backdrop = null;\n        }\n      };\n\n      _proto._showBackdrop = function _showBackdrop(callback) {\n        var _this8 = this;\n\n        var animate = $$$1(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : '';\n\n        if (this._isShown && this._config.backdrop) {\n          this._backdrop = document.createElement('div');\n          this._backdrop.className = ClassName.BACKDROP;\n\n          if (animate) {\n            this._backdrop.classList.add(animate);\n          }\n\n          $$$1(this._backdrop).appendTo(document.body);\n          $$$1(this._element).on(Event.CLICK_DISMISS, function (event) {\n            if (_this8._ignoreBackdropClick) {\n              _this8._ignoreBackdropClick = false;\n              return;\n            }\n\n            if (event.target !== event.currentTarget) {\n              return;\n            }\n\n            if (_this8._config.backdrop === 'static') {\n              _this8._element.focus();\n            } else {\n              _this8.hide();\n            }\n          });\n\n          if (animate) {\n            Util.reflow(this._backdrop);\n          }\n\n          $$$1(this._backdrop).addClass(ClassName.SHOW);\n\n          if (!callback) {\n            return;\n          }\n\n          if (!animate) {\n            callback();\n            return;\n          }\n\n          var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n          $$$1(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);\n        } else if (!this._isShown && this._backdrop) {\n          $$$1(this._backdrop).removeClass(ClassName.SHOW);\n\n          var callbackRemove = function callbackRemove() {\n            _this8._removeBackdrop();\n\n            if (callback) {\n              callback();\n            }\n          };\n\n          if ($$$1(this._element).hasClass(ClassName.FADE)) {\n            var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n\n            $$$1(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);\n          } else {\n            callbackRemove();\n          }\n        } else if (callback) {\n          callback();\n        }\n      }; // ----------------------------------------------------------------------\n      // the following methods are used to handle overflowing modals\n      // todo (fat): these should probably be refactored out of modal.js\n      // ----------------------------------------------------------------------\n\n\n      _proto._adjustDialog = function _adjustDialog() {\n        var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n        if (!this._isBodyOverflowing && isModalOverflowing) {\n          this._element.style.paddingLeft = this._scrollbarWidth + \"px\";\n        }\n\n        if (this._isBodyOverflowing && !isModalOverflowing) {\n          this._element.style.paddingRight = this._scrollbarWidth + \"px\";\n        }\n      };\n\n      _proto._resetAdjustments = function _resetAdjustments() {\n        this._element.style.paddingLeft = '';\n        this._element.style.paddingRight = '';\n      };\n\n      _proto._checkScrollbar = function _checkScrollbar() {\n        var rect = document.body.getBoundingClientRect();\n        this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;\n        this._scrollbarWidth = this._getScrollbarWidth();\n      };\n\n      _proto._setScrollbar = function _setScrollbar() {\n        var _this9 = this;\n\n        if (this._isBodyOverflowing) {\n          // Note: DOMNode.style.paddingRight returns the actual value or '' if not set\n          //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set\n          var fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT));\n          var stickyContent = [].slice.call(document.querySelectorAll(Selector.STICKY_CONTENT)); // Adjust fixed content padding\n\n          $$$1(fixedContent).each(function (index, element) {\n            var actualPadding = element.style.paddingRight;\n            var calculatedPadding = $$$1(element).css('padding-right');\n            $$$1(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + \"px\");\n          }); // Adjust sticky content margin\n\n          $$$1(stickyContent).each(function (index, element) {\n            var actualMargin = element.style.marginRight;\n            var calculatedMargin = $$$1(element).css('margin-right');\n            $$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + \"px\");\n          }); // Adjust body padding\n\n          var actualPadding = document.body.style.paddingRight;\n          var calculatedPadding = $$$1(document.body).css('padding-right');\n          $$$1(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + \"px\");\n        }\n      };\n\n      _proto._resetScrollbar = function _resetScrollbar() {\n        // Restore fixed content padding\n        var fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT));\n        $$$1(fixedContent).each(function (index, element) {\n          var padding = $$$1(element).data('padding-right');\n          $$$1(element).removeData('padding-right');\n          element.style.paddingRight = padding ? padding : '';\n        }); // Restore sticky content\n\n        var elements = [].slice.call(document.querySelectorAll(\"\" + Selector.STICKY_CONTENT));\n        $$$1(elements).each(function (index, element) {\n          var margin = $$$1(element).data('margin-right');\n\n          if (typeof margin !== 'undefined') {\n            $$$1(element).css('margin-right', margin).removeData('margin-right');\n          }\n        }); // Restore body padding\n\n        var padding = $$$1(document.body).data('padding-right');\n        $$$1(document.body).removeData('padding-right');\n        document.body.style.paddingRight = padding ? padding : '';\n      };\n\n      _proto._getScrollbarWidth = function _getScrollbarWidth() {\n        // thx d.walsh\n        var scrollDiv = document.createElement('div');\n        scrollDiv.className = ClassName.SCROLLBAR_MEASURER;\n        document.body.appendChild(scrollDiv);\n        var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;\n        document.body.removeChild(scrollDiv);\n        return scrollbarWidth;\n      }; // Static\n\n\n      Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          var _config = _objectSpread({}, Default, $$$1(this).data(), typeof config === 'object' && config ? config : {});\n\n          if (!data) {\n            data = new Modal(this, _config);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config](relatedTarget);\n          } else if (_config.show) {\n            data.show(relatedTarget);\n          }\n        });\n      };\n\n      _createClass(Modal, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }]);\n\n      return Modal;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {\n      var _this10 = this;\n\n      var target;\n      var selector = Util.getSelectorFromElement(this);\n\n      if (selector) {\n        target = document.querySelector(selector);\n      }\n\n      var config = $$$1(target).data(DATA_KEY) ? 'toggle' : _objectSpread({}, $$$1(target).data(), $$$1(this).data());\n\n      if (this.tagName === 'A' || this.tagName === 'AREA') {\n        event.preventDefault();\n      }\n\n      var $target = $$$1(target).one(Event.SHOW, function (showEvent) {\n        if (showEvent.isDefaultPrevented()) {\n          // Only register focus restorer if modal will actually get shown\n          return;\n        }\n\n        $target.one(Event.HIDDEN, function () {\n          if ($$$1(_this10).is(':visible')) {\n            _this10.focus();\n          }\n        });\n      });\n\n      Modal._jQueryInterface.call($$$1(target), config, this);\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Modal._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Modal;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Modal._jQueryInterface;\n    };\n\n    return Modal;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): tooltip.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Tooltip = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'tooltip';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.tooltip';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var CLASS_PREFIX = 'bs-tooltip';\n    var BSCLS_PREFIX_REGEX = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX + \"\\\\S+\", 'g');\n    var DefaultType = {\n      animation: 'boolean',\n      template: 'string',\n      title: '(string|element|function)',\n      trigger: 'string',\n      delay: '(number|object)',\n      html: 'boolean',\n      selector: '(string|boolean)',\n      placement: '(string|function)',\n      offset: '(number|string)',\n      container: '(string|element|boolean)',\n      fallbackPlacement: '(string|array)',\n      boundary: '(string|element)'\n    };\n    var AttachmentMap = {\n      AUTO: 'auto',\n      TOP: 'top',\n      RIGHT: 'right',\n      BOTTOM: 'bottom',\n      LEFT: 'left'\n    };\n    var Default = {\n      animation: true,\n      template: '<div class=\"tooltip\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<div class=\"tooltip-inner\"></div></div>',\n      trigger: 'hover focus',\n      title: '',\n      delay: 0,\n      html: false,\n      selector: false,\n      placement: 'top',\n      offset: 0,\n      container: false,\n      fallbackPlacement: 'flip',\n      boundary: 'scrollParent'\n    };\n    var HoverState = {\n      SHOW: 'show',\n      OUT: 'out'\n    };\n    var Event = {\n      HIDE: \"hide\" + EVENT_KEY,\n      HIDDEN: \"hidden\" + EVENT_KEY,\n      SHOW: \"show\" + EVENT_KEY,\n      SHOWN: \"shown\" + EVENT_KEY,\n      INSERTED: \"inserted\" + EVENT_KEY,\n      CLICK: \"click\" + EVENT_KEY,\n      FOCUSIN: \"focusin\" + EVENT_KEY,\n      FOCUSOUT: \"focusout\" + EVENT_KEY,\n      MOUSEENTER: \"mouseenter\" + EVENT_KEY,\n      MOUSELEAVE: \"mouseleave\" + EVENT_KEY\n    };\n    var ClassName = {\n      FADE: 'fade',\n      SHOW: 'show'\n    };\n    var Selector = {\n      TOOLTIP: '.tooltip',\n      TOOLTIP_INNER: '.tooltip-inner',\n      ARROW: '.arrow'\n    };\n    var Trigger = {\n      HOVER: 'hover',\n      FOCUS: 'focus',\n      CLICK: 'click',\n      MANUAL: 'manual'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Tooltip =\n    /*#__PURE__*/\n    function () {\n      function Tooltip(element, config) {\n        /**\n         * Check for Popper dependency\n         * Popper - https://popper.js.org\n         */\n        if (typeof Popper === 'undefined') {\n          throw new TypeError('Bootstrap tooltips require Popper.js (https://popper.js.org)');\n        } // private\n\n\n        this._isEnabled = true;\n        this._timeout = 0;\n        this._hoverState = '';\n        this._activeTrigger = {};\n        this._popper = null; // Protected\n\n        this.element = element;\n        this.config = this._getConfig(config);\n        this.tip = null;\n\n        this._setListeners();\n      } // Getters\n\n\n      var _proto = Tooltip.prototype;\n\n      // Public\n      _proto.enable = function enable() {\n        this._isEnabled = true;\n      };\n\n      _proto.disable = function disable() {\n        this._isEnabled = false;\n      };\n\n      _proto.toggleEnabled = function toggleEnabled() {\n        this._isEnabled = !this._isEnabled;\n      };\n\n      _proto.toggle = function toggle(event) {\n        if (!this._isEnabled) {\n          return;\n        }\n\n        if (event) {\n          var dataKey = this.constructor.DATA_KEY;\n          var context = $$$1(event.currentTarget).data(dataKey);\n\n          if (!context) {\n            context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n            $$$1(event.currentTarget).data(dataKey, context);\n          }\n\n          context._activeTrigger.click = !context._activeTrigger.click;\n\n          if (context._isWithActiveTrigger()) {\n            context._enter(null, context);\n          } else {\n            context._leave(null, context);\n          }\n        } else {\n          if ($$$1(this.getTipElement()).hasClass(ClassName.SHOW)) {\n            this._leave(null, this);\n\n            return;\n          }\n\n          this._enter(null, this);\n        }\n      };\n\n      _proto.dispose = function dispose() {\n        clearTimeout(this._timeout);\n        $$$1.removeData(this.element, this.constructor.DATA_KEY);\n        $$$1(this.element).off(this.constructor.EVENT_KEY);\n        $$$1(this.element).closest('.modal').off('hide.bs.modal');\n\n        if (this.tip) {\n          $$$1(this.tip).remove();\n        }\n\n        this._isEnabled = null;\n        this._timeout = null;\n        this._hoverState = null;\n        this._activeTrigger = null;\n\n        if (this._popper !== null) {\n          this._popper.destroy();\n        }\n\n        this._popper = null;\n        this.element = null;\n        this.config = null;\n        this.tip = null;\n      };\n\n      _proto.show = function show() {\n        var _this = this;\n\n        if ($$$1(this.element).css('display') === 'none') {\n          throw new Error('Please use show on visible elements');\n        }\n\n        var showEvent = $$$1.Event(this.constructor.Event.SHOW);\n\n        if (this.isWithContent() && this._isEnabled) {\n          $$$1(this.element).trigger(showEvent);\n          var isInTheDom = $$$1.contains(this.element.ownerDocument.documentElement, this.element);\n\n          if (showEvent.isDefaultPrevented() || !isInTheDom) {\n            return;\n          }\n\n          var tip = this.getTipElement();\n          var tipId = Util.getUID(this.constructor.NAME);\n          tip.setAttribute('id', tipId);\n          this.element.setAttribute('aria-describedby', tipId);\n          this.setContent();\n\n          if (this.config.animation) {\n            $$$1(tip).addClass(ClassName.FADE);\n          }\n\n          var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;\n\n          var attachment = this._getAttachment(placement);\n\n          this.addAttachmentClass(attachment);\n          var container = this.config.container === false ? document.body : $$$1(document).find(this.config.container);\n          $$$1(tip).data(this.constructor.DATA_KEY, this);\n\n          if (!$$$1.contains(this.element.ownerDocument.documentElement, this.tip)) {\n            $$$1(tip).appendTo(container);\n          }\n\n          $$$1(this.element).trigger(this.constructor.Event.INSERTED);\n          this._popper = new Popper(this.element, tip, {\n            placement: attachment,\n            modifiers: {\n              offset: {\n                offset: this.config.offset\n              },\n              flip: {\n                behavior: this.config.fallbackPlacement\n              },\n              arrow: {\n                element: Selector.ARROW\n              },\n              preventOverflow: {\n                boundariesElement: this.config.boundary\n              }\n            },\n            onCreate: function onCreate(data) {\n              if (data.originalPlacement !== data.placement) {\n                _this._handlePopperPlacementChange(data);\n              }\n            },\n            onUpdate: function onUpdate(data) {\n              _this._handlePopperPlacementChange(data);\n            }\n          });\n          $$$1(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra\n          // empty mouseover listeners to the body's immediate children;\n          // only needed because of broken event delegation on iOS\n          // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n          if ('ontouchstart' in document.documentElement) {\n            $$$1(document.body).children().on('mouseover', null, $$$1.noop);\n          }\n\n          var complete = function complete() {\n            if (_this.config.animation) {\n              _this._fixTransition();\n            }\n\n            var prevHoverState = _this._hoverState;\n            _this._hoverState = null;\n            $$$1(_this.element).trigger(_this.constructor.Event.SHOWN);\n\n            if (prevHoverState === HoverState.OUT) {\n              _this._leave(null, _this);\n            }\n          };\n\n          if ($$$1(this.tip).hasClass(ClassName.FADE)) {\n            var transitionDuration = Util.getTransitionDurationFromElement(this.tip);\n            $$$1(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n          } else {\n            complete();\n          }\n        }\n      };\n\n      _proto.hide = function hide(callback) {\n        var _this2 = this;\n\n        var tip = this.getTipElement();\n        var hideEvent = $$$1.Event(this.constructor.Event.HIDE);\n\n        var complete = function complete() {\n          if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {\n            tip.parentNode.removeChild(tip);\n          }\n\n          _this2._cleanTipClass();\n\n          _this2.element.removeAttribute('aria-describedby');\n\n          $$$1(_this2.element).trigger(_this2.constructor.Event.HIDDEN);\n\n          if (_this2._popper !== null) {\n            _this2._popper.destroy();\n          }\n\n          if (callback) {\n            callback();\n          }\n        };\n\n        $$$1(this.element).trigger(hideEvent);\n\n        if (hideEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        $$$1(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra\n        // empty mouseover listeners we added for iOS support\n\n        if ('ontouchstart' in document.documentElement) {\n          $$$1(document.body).children().off('mouseover', null, $$$1.noop);\n        }\n\n        this._activeTrigger[Trigger.CLICK] = false;\n        this._activeTrigger[Trigger.FOCUS] = false;\n        this._activeTrigger[Trigger.HOVER] = false;\n\n        if ($$$1(this.tip).hasClass(ClassName.FADE)) {\n          var transitionDuration = Util.getTransitionDurationFromElement(tip);\n          $$$1(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n        } else {\n          complete();\n        }\n\n        this._hoverState = '';\n      };\n\n      _proto.update = function update() {\n        if (this._popper !== null) {\n          this._popper.scheduleUpdate();\n        }\n      }; // Protected\n\n\n      _proto.isWithContent = function isWithContent() {\n        return Boolean(this.getTitle());\n      };\n\n      _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n        $$$1(this.getTipElement()).addClass(CLASS_PREFIX + \"-\" + attachment);\n      };\n\n      _proto.getTipElement = function getTipElement() {\n        this.tip = this.tip || $$$1(this.config.template)[0];\n        return this.tip;\n      };\n\n      _proto.setContent = function setContent() {\n        var tip = this.getTipElement();\n        this.setElementContent($$$1(tip.querySelectorAll(Selector.TOOLTIP_INNER)), this.getTitle());\n        $$$1(tip).removeClass(ClassName.FADE + \" \" + ClassName.SHOW);\n      };\n\n      _proto.setElementContent = function setElementContent($element, content) {\n        var html = this.config.html;\n\n        if (typeof content === 'object' && (content.nodeType || content.jquery)) {\n          // Content is a DOM node or a jQuery\n          if (html) {\n            if (!$$$1(content).parent().is($element)) {\n              $element.empty().append(content);\n            }\n          } else {\n            $element.text($$$1(content).text());\n          }\n        } else {\n          $element[html ? 'html' : 'text'](content);\n        }\n      };\n\n      _proto.getTitle = function getTitle() {\n        var title = this.element.getAttribute('data-original-title');\n\n        if (!title) {\n          title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;\n        }\n\n        return title;\n      }; // Private\n\n\n      _proto._getAttachment = function _getAttachment(placement) {\n        return AttachmentMap[placement.toUpperCase()];\n      };\n\n      _proto._setListeners = function _setListeners() {\n        var _this3 = this;\n\n        var triggers = this.config.trigger.split(' ');\n        triggers.forEach(function (trigger) {\n          if (trigger === 'click') {\n            $$$1(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) {\n              return _this3.toggle(event);\n            });\n          } else if (trigger !== Trigger.MANUAL) {\n            var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN;\n            var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT;\n            $$$1(_this3.element).on(eventIn, _this3.config.selector, function (event) {\n              return _this3._enter(event);\n            }).on(eventOut, _this3.config.selector, function (event) {\n              return _this3._leave(event);\n            });\n          }\n\n          $$$1(_this3.element).closest('.modal').on('hide.bs.modal', function () {\n            return _this3.hide();\n          });\n        });\n\n        if (this.config.selector) {\n          this.config = _objectSpread({}, this.config, {\n            trigger: 'manual',\n            selector: ''\n          });\n        } else {\n          this._fixTitle();\n        }\n      };\n\n      _proto._fixTitle = function _fixTitle() {\n        var titleType = typeof this.element.getAttribute('data-original-title');\n\n        if (this.element.getAttribute('title') || titleType !== 'string') {\n          this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');\n          this.element.setAttribute('title', '');\n        }\n      };\n\n      _proto._enter = function _enter(event, context) {\n        var dataKey = this.constructor.DATA_KEY;\n        context = context || $$$1(event.currentTarget).data(dataKey);\n\n        if (!context) {\n          context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n          $$$1(event.currentTarget).data(dataKey, context);\n        }\n\n        if (event) {\n          context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;\n        }\n\n        if ($$$1(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) {\n          context._hoverState = HoverState.SHOW;\n          return;\n        }\n\n        clearTimeout(context._timeout);\n        context._hoverState = HoverState.SHOW;\n\n        if (!context.config.delay || !context.config.delay.show) {\n          context.show();\n          return;\n        }\n\n        context._timeout = setTimeout(function () {\n          if (context._hoverState === HoverState.SHOW) {\n            context.show();\n          }\n        }, context.config.delay.show);\n      };\n\n      _proto._leave = function _leave(event, context) {\n        var dataKey = this.constructor.DATA_KEY;\n        context = context || $$$1(event.currentTarget).data(dataKey);\n\n        if (!context) {\n          context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n          $$$1(event.currentTarget).data(dataKey, context);\n        }\n\n        if (event) {\n          context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;\n        }\n\n        if (context._isWithActiveTrigger()) {\n          return;\n        }\n\n        clearTimeout(context._timeout);\n        context._hoverState = HoverState.OUT;\n\n        if (!context.config.delay || !context.config.delay.hide) {\n          context.hide();\n          return;\n        }\n\n        context._timeout = setTimeout(function () {\n          if (context._hoverState === HoverState.OUT) {\n            context.hide();\n          }\n        }, context.config.delay.hide);\n      };\n\n      _proto._isWithActiveTrigger = function _isWithActiveTrigger() {\n        for (var trigger in this._activeTrigger) {\n          if (this._activeTrigger[trigger]) {\n            return true;\n          }\n        }\n\n        return false;\n      };\n\n      _proto._getConfig = function _getConfig(config) {\n        config = _objectSpread({}, this.constructor.Default, $$$1(this.element).data(), typeof config === 'object' && config ? config : {});\n\n        if (typeof config.delay === 'number') {\n          config.delay = {\n            show: config.delay,\n            hide: config.delay\n          };\n        }\n\n        if (typeof config.title === 'number') {\n          config.title = config.title.toString();\n        }\n\n        if (typeof config.content === 'number') {\n          config.content = config.content.toString();\n        }\n\n        Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);\n        return config;\n      };\n\n      _proto._getDelegateConfig = function _getDelegateConfig() {\n        var config = {};\n\n        if (this.config) {\n          for (var key in this.config) {\n            if (this.constructor.Default[key] !== this.config[key]) {\n              config[key] = this.config[key];\n            }\n          }\n        }\n\n        return config;\n      };\n\n      _proto._cleanTipClass = function _cleanTipClass() {\n        var $tip = $$$1(this.getTipElement());\n        var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);\n\n        if (tabClass !== null && tabClass.length) {\n          $tip.removeClass(tabClass.join(''));\n        }\n      };\n\n      _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {\n        var popperInstance = popperData.instance;\n        this.tip = popperInstance.popper;\n\n        this._cleanTipClass();\n\n        this.addAttachmentClass(this._getAttachment(popperData.placement));\n      };\n\n      _proto._fixTransition = function _fixTransition() {\n        var tip = this.getTipElement();\n        var initConfigAnimation = this.config.animation;\n\n        if (tip.getAttribute('x-placement') !== null) {\n          return;\n        }\n\n        $$$1(tip).removeClass(ClassName.FADE);\n        this.config.animation = false;\n        this.hide();\n        this.show();\n        this.config.animation = initConfigAnimation;\n      }; // Static\n\n\n      Tooltip._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          var _config = typeof config === 'object' && config;\n\n          if (!data && /dispose|hide/.test(config)) {\n            return;\n          }\n\n          if (!data) {\n            data = new Tooltip(this, _config);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config]();\n          }\n        });\n      };\n\n      _createClass(Tooltip, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }, {\n        key: \"NAME\",\n        get: function get() {\n          return NAME;\n        }\n      }, {\n        key: \"DATA_KEY\",\n        get: function get() {\n          return DATA_KEY;\n        }\n      }, {\n        key: \"Event\",\n        get: function get() {\n          return Event;\n        }\n      }, {\n        key: \"EVENT_KEY\",\n        get: function get() {\n          return EVENT_KEY;\n        }\n      }, {\n        key: \"DefaultType\",\n        get: function get() {\n          return DefaultType;\n        }\n      }]);\n\n      return Tooltip;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1.fn[NAME] = Tooltip._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Tooltip;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Tooltip._jQueryInterface;\n    };\n\n    return Tooltip;\n  }($, Popper);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): popover.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Popover = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'popover';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.popover';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var CLASS_PREFIX = 'bs-popover';\n    var BSCLS_PREFIX_REGEX = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX + \"\\\\S+\", 'g');\n\n    var Default = _objectSpread({}, Tooltip.Default, {\n      placement: 'right',\n      trigger: 'click',\n      content: '',\n      template: '<div class=\"popover\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<h3 class=\"popover-header\"></h3>' + '<div class=\"popover-body\"></div></div>'\n    });\n\n    var DefaultType = _objectSpread({}, Tooltip.DefaultType, {\n      content: '(string|element|function)'\n    });\n\n    var ClassName = {\n      FADE: 'fade',\n      SHOW: 'show'\n    };\n    var Selector = {\n      TITLE: '.popover-header',\n      CONTENT: '.popover-body'\n    };\n    var Event = {\n      HIDE: \"hide\" + EVENT_KEY,\n      HIDDEN: \"hidden\" + EVENT_KEY,\n      SHOW: \"show\" + EVENT_KEY,\n      SHOWN: \"shown\" + EVENT_KEY,\n      INSERTED: \"inserted\" + EVENT_KEY,\n      CLICK: \"click\" + EVENT_KEY,\n      FOCUSIN: \"focusin\" + EVENT_KEY,\n      FOCUSOUT: \"focusout\" + EVENT_KEY,\n      MOUSEENTER: \"mouseenter\" + EVENT_KEY,\n      MOUSELEAVE: \"mouseleave\" + EVENT_KEY\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Popover =\n    /*#__PURE__*/\n    function (_Tooltip) {\n      _inheritsLoose(Popover, _Tooltip);\n\n      function Popover() {\n        return _Tooltip.apply(this, arguments) || this;\n      }\n\n      var _proto = Popover.prototype;\n\n      // Overrides\n      _proto.isWithContent = function isWithContent() {\n        return this.getTitle() || this._getContent();\n      };\n\n      _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n        $$$1(this.getTipElement()).addClass(CLASS_PREFIX + \"-\" + attachment);\n      };\n\n      _proto.getTipElement = function getTipElement() {\n        this.tip = this.tip || $$$1(this.config.template)[0];\n        return this.tip;\n      };\n\n      _proto.setContent = function setContent() {\n        var $tip = $$$1(this.getTipElement()); // We use append for html objects to maintain js events\n\n        this.setElementContent($tip.find(Selector.TITLE), this.getTitle());\n\n        var content = this._getContent();\n\n        if (typeof content === 'function') {\n          content = content.call(this.element);\n        }\n\n        this.setElementContent($tip.find(Selector.CONTENT), content);\n        $tip.removeClass(ClassName.FADE + \" \" + ClassName.SHOW);\n      }; // Private\n\n\n      _proto._getContent = function _getContent() {\n        return this.element.getAttribute('data-content') || this.config.content;\n      };\n\n      _proto._cleanTipClass = function _cleanTipClass() {\n        var $tip = $$$1(this.getTipElement());\n        var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);\n\n        if (tabClass !== null && tabClass.length > 0) {\n          $tip.removeClass(tabClass.join(''));\n        }\n      }; // Static\n\n\n      Popover._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          var _config = typeof config === 'object' ? config : null;\n\n          if (!data && /destroy|hide/.test(config)) {\n            return;\n          }\n\n          if (!data) {\n            data = new Popover(this, _config);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config]();\n          }\n        });\n      };\n\n      _createClass(Popover, null, [{\n        key: \"VERSION\",\n        // Getters\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }, {\n        key: \"NAME\",\n        get: function get() {\n          return NAME;\n        }\n      }, {\n        key: \"DATA_KEY\",\n        get: function get() {\n          return DATA_KEY;\n        }\n      }, {\n        key: \"Event\",\n        get: function get() {\n          return Event;\n        }\n      }, {\n        key: \"EVENT_KEY\",\n        get: function get() {\n          return EVENT_KEY;\n        }\n      }, {\n        key: \"DefaultType\",\n        get: function get() {\n          return DefaultType;\n        }\n      }]);\n\n      return Popover;\n    }(Tooltip);\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1.fn[NAME] = Popover._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Popover;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Popover._jQueryInterface;\n    };\n\n    return Popover;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): scrollspy.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var ScrollSpy = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'scrollspy';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.scrollspy';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var Default = {\n      offset: 10,\n      method: 'auto',\n      target: ''\n    };\n    var DefaultType = {\n      offset: 'number',\n      method: 'string',\n      target: '(string|element)'\n    };\n    var Event = {\n      ACTIVATE: \"activate\" + EVENT_KEY,\n      SCROLL: \"scroll\" + EVENT_KEY,\n      LOAD_DATA_API: \"load\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      DROPDOWN_ITEM: 'dropdown-item',\n      DROPDOWN_MENU: 'dropdown-menu',\n      ACTIVE: 'active'\n    };\n    var Selector = {\n      DATA_SPY: '[data-spy=\"scroll\"]',\n      ACTIVE: '.active',\n      NAV_LIST_GROUP: '.nav, .list-group',\n      NAV_LINKS: '.nav-link',\n      NAV_ITEMS: '.nav-item',\n      LIST_ITEMS: '.list-group-item',\n      DROPDOWN: '.dropdown',\n      DROPDOWN_ITEMS: '.dropdown-item',\n      DROPDOWN_TOGGLE: '.dropdown-toggle'\n    };\n    var OffsetMethod = {\n      OFFSET: 'offset',\n      POSITION: 'position'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var ScrollSpy =\n    /*#__PURE__*/\n    function () {\n      function ScrollSpy(element, config) {\n        var _this = this;\n\n        this._element = element;\n        this._scrollElement = element.tagName === 'BODY' ? window : element;\n        this._config = this._getConfig(config);\n        this._selector = this._config.target + \" \" + Selector.NAV_LINKS + \",\" + (this._config.target + \" \" + Selector.LIST_ITEMS + \",\") + (this._config.target + \" \" + Selector.DROPDOWN_ITEMS);\n        this._offsets = [];\n        this._targets = [];\n        this._activeTarget = null;\n        this._scrollHeight = 0;\n        $$$1(this._scrollElement).on(Event.SCROLL, function (event) {\n          return _this._process(event);\n        });\n        this.refresh();\n\n        this._process();\n      } // Getters\n\n\n      var _proto = ScrollSpy.prototype;\n\n      // Public\n      _proto.refresh = function refresh() {\n        var _this2 = this;\n\n        var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;\n        var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;\n        var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;\n        this._offsets = [];\n        this._targets = [];\n        this._scrollHeight = this._getScrollHeight();\n        var targets = [].slice.call(document.querySelectorAll(this._selector));\n        targets.map(function (element) {\n          var target;\n          var targetSelector = Util.getSelectorFromElement(element);\n\n          if (targetSelector) {\n            target = document.querySelector(targetSelector);\n          }\n\n          if (target) {\n            var targetBCR = target.getBoundingClientRect();\n\n            if (targetBCR.width || targetBCR.height) {\n              // TODO (fat): remove sketch reliance on jQuery position/offset\n              return [$$$1(target)[offsetMethod]().top + offsetBase, targetSelector];\n            }\n          }\n\n          return null;\n        }).filter(function (item) {\n          return item;\n        }).sort(function (a, b) {\n          return a[0] - b[0];\n        }).forEach(function (item) {\n          _this2._offsets.push(item[0]);\n\n          _this2._targets.push(item[1]);\n        });\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        $$$1(this._scrollElement).off(EVENT_KEY);\n        this._element = null;\n        this._scrollElement = null;\n        this._config = null;\n        this._selector = null;\n        this._offsets = null;\n        this._targets = null;\n        this._activeTarget = null;\n        this._scrollHeight = null;\n      }; // Private\n\n\n      _proto._getConfig = function _getConfig(config) {\n        config = _objectSpread({}, Default, typeof config === 'object' && config ? config : {});\n\n        if (typeof config.target !== 'string') {\n          var id = $$$1(config.target).attr('id');\n\n          if (!id) {\n            id = Util.getUID(NAME);\n            $$$1(config.target).attr('id', id);\n          }\n\n          config.target = \"#\" + id;\n        }\n\n        Util.typeCheckConfig(NAME, config, DefaultType);\n        return config;\n      };\n\n      _proto._getScrollTop = function _getScrollTop() {\n        return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;\n      };\n\n      _proto._getScrollHeight = function _getScrollHeight() {\n        return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);\n      };\n\n      _proto._getOffsetHeight = function _getOffsetHeight() {\n        return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;\n      };\n\n      _proto._process = function _process() {\n        var scrollTop = this._getScrollTop() + this._config.offset;\n\n        var scrollHeight = this._getScrollHeight();\n\n        var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();\n\n        if (this._scrollHeight !== scrollHeight) {\n          this.refresh();\n        }\n\n        if (scrollTop >= maxScroll) {\n          var target = this._targets[this._targets.length - 1];\n\n          if (this._activeTarget !== target) {\n            this._activate(target);\n          }\n\n          return;\n        }\n\n        if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n          this._activeTarget = null;\n\n          this._clear();\n\n          return;\n        }\n\n        var offsetLength = this._offsets.length;\n\n        for (var i = offsetLength; i--;) {\n          var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);\n\n          if (isActiveTarget) {\n            this._activate(this._targets[i]);\n          }\n        }\n      };\n\n      _proto._activate = function _activate(target) {\n        this._activeTarget = target;\n\n        this._clear();\n\n        var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style\n\n\n        queries = queries.map(function (selector) {\n          return selector + \"[data-target=\\\"\" + target + \"\\\"],\" + (selector + \"[href=\\\"\" + target + \"\\\"]\");\n        });\n        var $link = $$$1([].slice.call(document.querySelectorAll(queries.join(','))));\n\n        if ($link.hasClass(ClassName.DROPDOWN_ITEM)) {\n          $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);\n          $link.addClass(ClassName.ACTIVE);\n        } else {\n          // Set triggered link as active\n          $link.addClass(ClassName.ACTIVE); // Set triggered links parents as active\n          // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n\n          $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + \", \" + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE); // Handle special case when .nav-link is inside .nav-item\n\n          $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE);\n        }\n\n        $$$1(this._scrollElement).trigger(Event.ACTIVATE, {\n          relatedTarget: target\n        });\n      };\n\n      _proto._clear = function _clear() {\n        var nodes = [].slice.call(document.querySelectorAll(this._selector));\n        $$$1(nodes).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);\n      }; // Static\n\n\n      ScrollSpy._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var data = $$$1(this).data(DATA_KEY);\n\n          var _config = typeof config === 'object' && config;\n\n          if (!data) {\n            data = new ScrollSpy(this, _config);\n            $$$1(this).data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config]();\n          }\n        });\n      };\n\n      _createClass(ScrollSpy, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }, {\n        key: \"Default\",\n        get: function get() {\n          return Default;\n        }\n      }]);\n\n      return ScrollSpy;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(window).on(Event.LOAD_DATA_API, function () {\n      var scrollSpys = [].slice.call(document.querySelectorAll(Selector.DATA_SPY));\n      var scrollSpysLength = scrollSpys.length;\n\n      for (var i = scrollSpysLength; i--;) {\n        var $spy = $$$1(scrollSpys[i]);\n\n        ScrollSpy._jQueryInterface.call($spy, $spy.data());\n      }\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = ScrollSpy._jQueryInterface;\n    $$$1.fn[NAME].Constructor = ScrollSpy;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return ScrollSpy._jQueryInterface;\n    };\n\n    return ScrollSpy;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): tab.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  var Tab = function ($$$1) {\n    /**\n     * ------------------------------------------------------------------------\n     * Constants\n     * ------------------------------------------------------------------------\n     */\n    var NAME = 'tab';\n    var VERSION = '4.1.3';\n    var DATA_KEY = 'bs.tab';\n    var EVENT_KEY = \".\" + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $$$1.fn[NAME];\n    var Event = {\n      HIDE: \"hide\" + EVENT_KEY,\n      HIDDEN: \"hidden\" + EVENT_KEY,\n      SHOW: \"show\" + EVENT_KEY,\n      SHOWN: \"shown\" + EVENT_KEY,\n      CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n    };\n    var ClassName = {\n      DROPDOWN_MENU: 'dropdown-menu',\n      ACTIVE: 'active',\n      DISABLED: 'disabled',\n      FADE: 'fade',\n      SHOW: 'show'\n    };\n    var Selector = {\n      DROPDOWN: '.dropdown',\n      NAV_LIST_GROUP: '.nav, .list-group',\n      ACTIVE: '.active',\n      ACTIVE_UL: '> li > .active',\n      DATA_TOGGLE: '[data-toggle=\"tab\"], [data-toggle=\"pill\"], [data-toggle=\"list\"]',\n      DROPDOWN_TOGGLE: '.dropdown-toggle',\n      DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'\n      /**\n       * ------------------------------------------------------------------------\n       * Class Definition\n       * ------------------------------------------------------------------------\n       */\n\n    };\n\n    var Tab =\n    /*#__PURE__*/\n    function () {\n      function Tab(element) {\n        this._element = element;\n      } // Getters\n\n\n      var _proto = Tab.prototype;\n\n      // Public\n      _proto.show = function show() {\n        var _this = this;\n\n        if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $$$1(this._element).hasClass(ClassName.ACTIVE) || $$$1(this._element).hasClass(ClassName.DISABLED)) {\n          return;\n        }\n\n        var target;\n        var previous;\n        var listElement = $$$1(this._element).closest(Selector.NAV_LIST_GROUP)[0];\n        var selector = Util.getSelectorFromElement(this._element);\n\n        if (listElement) {\n          var itemSelector = listElement.nodeName === 'UL' ? Selector.ACTIVE_UL : Selector.ACTIVE;\n          previous = $$$1.makeArray($$$1(listElement).find(itemSelector));\n          previous = previous[previous.length - 1];\n        }\n\n        var hideEvent = $$$1.Event(Event.HIDE, {\n          relatedTarget: this._element\n        });\n        var showEvent = $$$1.Event(Event.SHOW, {\n          relatedTarget: previous\n        });\n\n        if (previous) {\n          $$$1(previous).trigger(hideEvent);\n        }\n\n        $$$1(this._element).trigger(showEvent);\n\n        if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        if (selector) {\n          target = document.querySelector(selector);\n        }\n\n        this._activate(this._element, listElement);\n\n        var complete = function complete() {\n          var hiddenEvent = $$$1.Event(Event.HIDDEN, {\n            relatedTarget: _this._element\n          });\n          var shownEvent = $$$1.Event(Event.SHOWN, {\n            relatedTarget: previous\n          });\n          $$$1(previous).trigger(hiddenEvent);\n          $$$1(_this._element).trigger(shownEvent);\n        };\n\n        if (target) {\n          this._activate(target, target.parentNode, complete);\n        } else {\n          complete();\n        }\n      };\n\n      _proto.dispose = function dispose() {\n        $$$1.removeData(this._element, DATA_KEY);\n        this._element = null;\n      }; // Private\n\n\n      _proto._activate = function _activate(element, container, callback) {\n        var _this2 = this;\n\n        var activeElements;\n\n        if (container.nodeName === 'UL') {\n          activeElements = $$$1(container).find(Selector.ACTIVE_UL);\n        } else {\n          activeElements = $$$1(container).children(Selector.ACTIVE);\n        }\n\n        var active = activeElements[0];\n        var isTransitioning = callback && active && $$$1(active).hasClass(ClassName.FADE);\n\n        var complete = function complete() {\n          return _this2._transitionComplete(element, active, callback);\n        };\n\n        if (active && isTransitioning) {\n          var transitionDuration = Util.getTransitionDurationFromElement(active);\n          $$$1(active).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n        } else {\n          complete();\n        }\n      };\n\n      _proto._transitionComplete = function _transitionComplete(element, active, callback) {\n        if (active) {\n          $$$1(active).removeClass(ClassName.SHOW + \" \" + ClassName.ACTIVE);\n          var dropdownChild = $$$1(active.parentNode).find(Selector.DROPDOWN_ACTIVE_CHILD)[0];\n\n          if (dropdownChild) {\n            $$$1(dropdownChild).removeClass(ClassName.ACTIVE);\n          }\n\n          if (active.getAttribute('role') === 'tab') {\n            active.setAttribute('aria-selected', false);\n          }\n        }\n\n        $$$1(element).addClass(ClassName.ACTIVE);\n\n        if (element.getAttribute('role') === 'tab') {\n          element.setAttribute('aria-selected', true);\n        }\n\n        Util.reflow(element);\n        $$$1(element).addClass(ClassName.SHOW);\n\n        if (element.parentNode && $$$1(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) {\n          var dropdownElement = $$$1(element).closest(Selector.DROPDOWN)[0];\n\n          if (dropdownElement) {\n            var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector.DROPDOWN_TOGGLE));\n            $$$1(dropdownToggleList).addClass(ClassName.ACTIVE);\n          }\n\n          element.setAttribute('aria-expanded', true);\n        }\n\n        if (callback) {\n          callback();\n        }\n      }; // Static\n\n\n      Tab._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var $this = $$$1(this);\n          var data = $this.data(DATA_KEY);\n\n          if (!data) {\n            data = new Tab(this);\n            $this.data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (typeof data[config] === 'undefined') {\n              throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n            }\n\n            data[config]();\n          }\n        });\n      };\n\n      _createClass(Tab, null, [{\n        key: \"VERSION\",\n        get: function get() {\n          return VERSION;\n        }\n      }]);\n\n      return Tab;\n    }();\n    /**\n     * ------------------------------------------------------------------------\n     * Data Api implementation\n     * ------------------------------------------------------------------------\n     */\n\n\n    $$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {\n      event.preventDefault();\n\n      Tab._jQueryInterface.call($$$1(this), 'show');\n    });\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $$$1.fn[NAME] = Tab._jQueryInterface;\n    $$$1.fn[NAME].Constructor = Tab;\n\n    $$$1.fn[NAME].noConflict = function () {\n      $$$1.fn[NAME] = JQUERY_NO_CONFLICT;\n      return Tab._jQueryInterface;\n    };\n\n    return Tab;\n  }($);\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.1.3): index.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  (function ($$$1) {\n    if (typeof $$$1 === 'undefined') {\n      throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.');\n    }\n\n    var version = $$$1.fn.jquery.split(' ')[0].split('.');\n    var minMajor = 1;\n    var ltMajor = 2;\n    var minMinor = 9;\n    var minPatch = 1;\n    var maxMajor = 4;\n\n    if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n      throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');\n    }\n  })($);\n\n  exports.Util = Util;\n  exports.Alert = Alert;\n  exports.Button = Button;\n  exports.Carousel = Carousel;\n  exports.Collapse = Collapse;\n  exports.Dropdown = Dropdown;\n  exports.Modal = Modal;\n  exports.Popover = Popover;\n  exports.Scrollspy = ScrollSpy;\n  exports.Tab = Tab;\n  exports.Tooltip = Tooltip;\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=bootstrap.js.map\n"
  },
  {
    "path": "src/main/webapp/static/bootstrap/css/bootstrap-theme.css",
    "content": "/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n  text-shadow: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n}\n.btn-default {\n  text-shadow: 0 1px 0 #fff;\n  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));\n  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #dbdbdb;\n  border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n  background-color: #e0e0e0;\n  background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n  background-color: #e0e0e0;\n  border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #e0e0e0;\n  background-image: none;\n}\n.btn-primary {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n  background-color: #265a88;\n  background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #265a88;\n  border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #265a88;\n  background-image: none;\n}\n.btn-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));\n  background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n  background-color: #419641;\n  background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n  background-color: #419641;\n  border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #419641;\n  background-image: none;\n}\n.btn-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));\n  background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n  background-color: #2aabd2;\n  background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n  background-color: #2aabd2;\n  border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #2aabd2;\n  background-image: none;\n}\n.btn-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));\n  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n  background-color: #eb9316;\n  background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #eb9316;\n  border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #eb9316;\n  background-image: none;\n}\n.btn-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));\n  background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n  background-color: #c12e2a;\n  background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #c12e2a;\n  border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #c12e2a;\n  background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  background-color: #e8e8e8;\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-repeat: repeat-x;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  background-color: #2e6da4;\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n  background-repeat: repeat-x;\n}\n.navbar-default {\n  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);\n  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));\n  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));\n  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n  background-repeat: repeat-x;\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);\n}\n.navbar-inverse {\n  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));\n  background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n  background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));\n  background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n  background-repeat: repeat-x;\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);\n          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n@media (max-width: 767px) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n    background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n    background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n    background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n    background-repeat: repeat-x;\n  }\n}\n.alert {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n}\n.alert-success {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));\n  background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #b2dba1;\n}\n.alert-info {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));\n  background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #9acfea;\n}\n.alert-warning {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));\n  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #f5e79e;\n}\n.alert-danger {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));\n  background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #dca7a7;\n}\n.progress {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));\n  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));\n  background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));\n  background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));\n  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));\n  background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.list-group {\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 #286090;\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n  text-shadow: none;\n}\n.panel {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n}\n.panel-default > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-primary > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-success > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));\n  background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-info > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));\n  background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-warning > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));\n  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-danger > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));\n  background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n  background-repeat: repeat-x;\n}\n.well {\n  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));\n  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #dcdcdc;\n  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */\n"
  },
  {
    "path": "src/main/webapp/static/bootstrap/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  margin: .67em 0;\n  font-size: 2em;\n}\nmark {\n  color: #000;\n  background: #ff0;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\nsup {\n  top: -.5em;\n}\nsub {\n  bottom: -.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  height: 0;\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  margin: 0;\n  font: inherit;\n  color: inherit;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  padding: .35em .625em .75em;\n  margin: 0 2px;\n  border: 1px solid #c0c0c0;\n}\nlegend {\n  padding: 0;\n  border: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-spacing: 0;\n  border-collapse: collapse;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    color: #000 !important;\n    text-shadow: none !important;\n    background: transparent !important;\n    -webkit-box-shadow: none !important;\n            box-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\002a\";\n}\n.glyphicon-plus:before {\n  content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333;\n  background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #337ab7;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #23527c;\n  text-decoration: underline;\n}\na:focus {\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all .2s ease-in-out;\n       -o-transition: all .2s ease-in-out;\n          transition: all .2s ease-in-out;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  padding: .2em;\n  background-color: #fcf8e3;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #777;\n}\n.text-primary {\n  color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #286090;\n}\n.text-success {\n  color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #2b542c;\n}\n.text-info {\n  color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #245269;\n}\n.text-warning {\n  color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #66512c;\n}\n.text-danger {\n  color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #843534;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #286090;\n}\n.bg-success {\n  background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #c1e2b3;\n}\n.bg-info {\n  background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #afd9ee;\n}\n.bg-warning {\n  background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f7ecb5;\n}\n.bg-danger {\n  background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #e4b9b9;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  margin-left: -5px;\n  list-style: none;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-right: 5px;\n  padding-left: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    overflow: hidden;\n    clear: left;\n    text-align: right;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  text-align: right;\n  border-right: 5px solid #eee;\n  border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #fff;\n  background-color: #333;\n  border-radius: 3px;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #333;\n  word-break: break-all;\n  word-wrap: break-word;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n.row {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0;\n  }\n}\ntable {\n  background-color: transparent;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #ddd;\n}\n.table .table {\n  background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  display: table-column;\n  float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  display: table-cell;\n  float: none;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n}\n.table-responsive {\n  min-height: .01%;\n  overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #ddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n  background-color: #fff;\n  background-image: none;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n}\n.form-control::-moz-placeholder {\n  color: #999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999;\n}\n.form-control::-ms-expand {\n  background-color: transparent;\n  border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eee;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"].form-control,\n  input[type=\"time\"].form-control,\n  input[type=\"datetime-local\"].form-control,\n  input[type=\"month\"].form-control {\n    line-height: 34px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 46px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-top: 4px \\9;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  vertical-align: middle;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  min-height: 34px;\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 46px;\n  line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 46px;\n  min-height: 38px;\n  padding: 11px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #3c763d;\n}\n.has-success .form-control {\n  border-color: #3c763d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-success .form-control:focus {\n  border-color: #2b542c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n  color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #8a6d3b;\n}\n.has-warning .form-control {\n  border-color: #8a6d3b;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-warning .form-control:focus {\n  border-color: #66512c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n  color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #a94442;\n}\n.has-error .form-control {\n  border-color: #a94442;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-error .form-control:focus {\n  border-color: #843534;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #a94442;\n}\n.has-error .form-control-feedback {\n  color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 7px;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    padding-top: 7px;\n    margin-bottom: 0;\n    text-align: right;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 11px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  padding: 6px 12px;\n  margin-bottom: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  -ms-touch-action: manipulation;\n      touch-action: manipulation;\n  cursor: pointer;\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  opacity: .65;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333;\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default .badge {\n  color: #fff;\n  background-color: #333;\n}\n.btn-primary {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #fff;\n  background-color: #286090;\n  border-color: #122b40;\n}\n.btn-primary:hover {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #fff;\n  background-color: #204d74;\n  border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.btn-success {\n  color: #fff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #255625;\n}\n.btn-success:hover {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #fff;\n  background-color: #398439;\n  border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success .badge {\n  color: #5cb85c;\n  background-color: #fff;\n}\n.btn-info {\n  color: #fff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #1b6d85;\n}\n.btn-info:hover {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #fff;\n  background-color: #269abc;\n  border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info .badge {\n  color: #5bc0de;\n  background-color: #fff;\n}\n.btn-warning {\n  color: #fff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #985f0d;\n}\n.btn-warning:hover {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #fff;\n  background-color: #d58512;\n  border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning .badge {\n  color: #f0ad4e;\n  background-color: #fff;\n}\n.btn-danger {\n  color: #fff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #761c19;\n}\n.btn-danger:hover {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #fff;\n  background-color: #ac2925;\n  border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger .badge {\n  color: #d9534f;\n  background-color: #fff;\n}\n.btn-link {\n  font-weight: normal;\n  color: #337ab7;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #23527c;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity .15s linear;\n       -o-transition: opacity .15s linear;\n          transition: opacity .15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-timing-function: ease;\n       -o-transition-timing-function: ease;\n          transition-timing-function: ease;\n  -webkit-transition-duration: .35s;\n       -o-transition-duration: .35s;\n          transition-duration: .35s;\n  -webkit-transition-property: height, visibility;\n       -o-transition-property: height, visibility;\n          transition-property: height, visibility;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-top: 4px solid \\9;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  font-size: 14px;\n  text-align: left;\n  list-style: none;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  background-color: #337ab7;\n  outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu-left {\n  right: auto;\n  left: 0;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  content: \"\";\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .navbar-right .dropdown-menu-left {\n    right: auto;\n    left: 0;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-right: 8px;\n  padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  display: table-cell;\n  float: none;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group .form-control:focus {\n  z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555;\n  text-align: center;\n  background-color: #eee;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.nav > li.disabled > a {\n  color: #777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777;\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eee;\n  border-color: #337ab7;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eee #eee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555;\n  cursor: default;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #fff;\n  background-color: #337ab7;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  padding-right: 15px;\n  padding-left: 15px;\n  overflow-x: visible;\n  -webkit-overflow-scrolling: touch;\n  border-top: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  height: 50px;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-right: 15px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n.navbar-form {\n  padding: 10px 15px;\n  margin-top: 8px;\n  margin-right: -15px;\n  margin-bottom: 8px;\n  margin-left: -15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    padding-top: 0;\n    padding-bottom: 0;\n    margin-right: 0;\n    margin-left: 0;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-right: 15px;\n    margin-left: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #ccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333;\n}\n.navbar-default .btn-link {\n  color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #ccc;\n}\n.navbar-inverse {\n  background-color: #222;\n  border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #fff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  padding: 0 5px;\n  color: #ccc;\n  content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n  color: #777;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  margin-left: -1px;\n  line-height: 1.42857143;\n  color: #337ab7;\n  text-decoration: none;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 2;\n  color: #23527c;\n  background-color: #eee;\n  border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 3;\n  color: #fff;\n  cursor: default;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n  border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-top-left-radius: 6px;\n  border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-top-right-radius: 6px;\n  border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  text-align: center;\n  list-style: none;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #286090;\n}\n.label-success {\n  background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #449d44;\n}\n.label-info {\n  background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.label-warning {\n  background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.label-danger {\n  background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  background-color: #777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding-top: 30px;\n  padding-bottom: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  padding-right: 15px;\n  padding-left: 15px;\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-right: 60px;\n    padding-left: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: border .2s ease-in-out;\n       -o-transition: border .2s ease-in-out;\n          transition: border .2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-right: auto;\n  margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #337ab7;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n  color: #2b542c;\n}\n.alert-info {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n  color: #245269;\n}\n.alert-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n  color: #66512c;\n}\n.alert-danger {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n  color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  height: 20px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n}\n.progress-bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  background-color: #337ab7;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n  -webkit-transition: width .6s ease;\n       -o-transition: width .6s ease;\n          transition: width .6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-object.img-thumbnail {\n  max-width: none;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  padding-left: 0;\n  margin-bottom: 20px;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n  color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  color: #555;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\nbutton.list-group-item {\n  width: 100%;\n  text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #eee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #c7ddef;\n}\n.list-group-item-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n  color: #3c763d;\n  background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3c763d;\n  border-color: #3c763d;\n}\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n  color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n  color: #31708f;\n  background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #31708f;\n  border-color: #31708f;\n}\n.list-group-item-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n  color: #8a6d3b;\n  background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #8a6d3b;\n  border-color: #8a6d3b;\n}\n.list-group-item-danger {\n  color: #a94442;\n  background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n  color: #a94442;\n  background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #a94442;\n  border-color: #a94442;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #fff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  margin-bottom: 0;\n  border: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #ddd;\n}\n.panel-default {\n  border-color: #ddd;\n}\n.panel-default > .panel-heading {\n  color: #333;\n  background-color: #f5f5f5;\n  border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ddd;\n}\n.panel-primary {\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #337ab7;\n}\n.panel-success {\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n  color: #dff0d8;\n  background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.panel-info {\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n  color: #d9edf7;\n  background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.panel-warning {\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n  color: #fcf8e3;\n  background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #faebcc;\n}\n.panel-danger {\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f2dede;\n  background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, .15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  filter: alpha(opacity=20);\n  opacity: .2;\n}\n.close:hover,\n.close:focus {\n  color: #000;\n  text-decoration: none;\n  cursor: pointer;\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\nbutton.close {\n  -webkit-appearance: none;\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  display: none;\n  overflow: hidden;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transition: -webkit-transform .3s ease-out;\n       -o-transition:      -o-transform .3s ease-out;\n          transition:         transform .3s ease-out;\n  -webkit-transform: translate(0, -25%);\n      -ms-transform: translate(0, -25%);\n       -o-transform: translate(0, -25%);\n          transform: translate(0, -25%);\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n      -ms-transform: translate(0, 0);\n       -o-transform: translate(0, 0);\n          transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  outline: 0;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000;\n}\n.modal-backdrop.fade {\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.modal-backdrop.in {\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  filter: alpha(opacity=0);\n  opacity: 0;\n\n  line-break: auto;\n}\n.tooltip.in {\n  filter: alpha(opacity=90);\n  opacity: .9;\n}\n.tooltip.top {\n  padding: 5px 0;\n  margin-top: -3px;\n}\n.tooltip.right {\n  padding: 0 5px;\n  margin-left: 3px;\n}\n.tooltip.bottom {\n  padding: 5px 0;\n  margin-top: 3px;\n}\n.tooltip.left {\n  padding: 0 5px;\n  margin-left: -3px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #fff;\n  text-align: center;\n  background-color: #000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n  right: 5px;\n  bottom: 0;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n\n  line-break: auto;\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  padding: 8px 14px;\n  margin: 0;\n  font-size: 14px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  content: \"\";\n  border-width: 10px;\n}\n.popover.top > .arrow {\n  bottom: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-color: #999;\n  border-top-color: rgba(0, 0, 0, .25);\n  border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n  bottom: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-color: #fff;\n  border-bottom-width: 0;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-right-color: #999;\n  border-right-color: rgba(0, 0, 0, .25);\n  border-left-width: 0;\n}\n.popover.right > .arrow:after {\n  bottom: -10px;\n  left: 1px;\n  content: \" \";\n  border-right-color: #fff;\n  border-left-width: 0;\n}\n.popover.bottom > .arrow {\n  top: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999;\n  border-bottom-color: rgba(0, 0, 0, .25);\n}\n.popover.bottom > .arrow:after {\n  top: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-width: 0;\n  border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999;\n  border-left-color: rgba(0, 0, 0, .25);\n}\n.popover.left > .arrow:after {\n  right: 1px;\n  bottom: -10px;\n  content: \" \";\n  border-right-width: 0;\n  border-left-color: #fff;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n.carousel-inner > .item {\n  position: relative;\n  display: none;\n  -webkit-transition: .6s ease-in-out left;\n       -o-transition: .6s ease-in-out left;\n          transition: .6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform .6s ease-in-out;\n         -o-transition:      -o-transform .6s ease-in-out;\n            transition:         transform .6s ease-in-out;\n\n    -webkit-backface-visibility: hidden;\n            backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n            perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    left: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n            transform: translate3d(100%, 0, 0);\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    left: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n            transform: translate3d(-100%, 0, 0);\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    left: 0;\n    -webkit-transform: translate3d(0, 0, 0);\n            transform: translate3d(0, 0, 0);\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 15%;\n  font-size: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n  background-color: rgba(0, 0, 0, 0);\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control.right {\n  right: 0;\n  left: auto;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #fff;\n  text-decoration: none;\n  filter: alpha(opacity=90);\n  outline: 0;\n  opacity: .9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n  margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  font-family: serif;\n  line-height: 1;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  padding-left: 0;\n  margin-left: -30%;\n  text-align: center;\n  list-style: none;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n  border: 1px solid #fff;\n  border-radius: 10px;\n}\n.carousel-indicators .active {\n  width: 12px;\n  height: 12px;\n  margin: 0;\n  background-color: #fff;\n}\n.carousel-caption {\n  position: absolute;\n  right: 15%;\n  bottom: 20px;\n  left: 15%;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -10px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -10px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -10px;\n  }\n  .carousel-caption {\n    right: 20%;\n    left: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-right: auto;\n  margin-left: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */\n"
  },
  {
    "path": "src/main/webapp/static/bootstrap/css/style.css",
    "content": "\nbody{background:#fff;color:#5B5B5D;font-family:\"Microsoft YaHei\",\"Segoe UI\",\"Lucida Grande\",Helvetica,Arial,sans-serif}\n*{margin:0;margin:0}\n.sucaihuo-container{margin:0 auto;text-align:center;overflow:hidden}\n.sucaihuo-header{padding:3em 190px 2em;letter-spacing:-1px;text-align:center}\n.sucaihuo-header h1{color:#404d5b;font-weight:600;font-size:2em;line-height:1;margin-bottom:0;font-family:\"Segoe UI\",\"Lucida Grande\",Helvetica,Arial,\"Microsoft YaHei\",FreeSans,Arimo,\"Droid Sans\",\"wenquanyi micro hei\",\"Hiragino Sans GB\",\"Hiragino Sans GB W3\",\"FontAwesome\",sans-serif}\n.sucaihuo-content{min-height:60vh;height:60vh;font-size:150%;padding:1em 0}\n.bgcolor-3{background:#e8e8e8}\n*,*:after,*:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n\n.form-bg{\n\tbackground: #00b4ef;\n}\n.form-horizontal{\n\tbackground: #fff;\n\tpadding-bottom: 40px;\n\tborder-radius: 15px;\n\ttext-align: center;\n}\n.form-horizontal .heading{\n\tdisplay: block;\n\tfont-size: 35px;\n\tfont-weight: 700;\n\tpadding: 35px 0;\n\tborder-bottom: 1px solid #f0f0f0;\n\tmargin-bottom: 30px;\n}\n.form-horizontal .form-group{\n\tpadding: 0 40px;\n\tmargin: 0 0 25px 0;\n\tposition: relative;\n}\n.form-horizontal .form-control{\n\tbackground: #f0f0f0;\n\tborder: none;\n\tborder-radius: 20px;\n\tbox-shadow: none;\n\tpadding: 0 20px 0 45px;\n\theight: 40px;\n\ttransition: all 0.3s ease 0s;\n}\n.form-horizontal .form-control:focus{\n\tbackground: #e0e0e0;\n\tbox-shadow: none;\n\toutline: 0 none;\n}\n.form-horizontal .form-group i{\n\tposition: absolute;\n\ttop: 12px;\n\tleft: 60px;\n\tfont-size: 17px;\n\tcolor: #c8c8c8;\n\ttransition : all 0.5s ease 0s;\n}\n.form-horizontal .form-control:focus + i{\n\tcolor: #00b4ef;\n}\n.form-horizontal .fa-question-circle{\n\tdisplay: inline-block;\n\tposition: absolute;\n\ttop: 12px;\n\tright: 60px;\n\tfont-size: 20px;\n\tcolor: #808080;\n\ttransition: all 0.5s ease 0s;\n}\n.form-horizontal .fa-question-circle:hover{\n\tcolor: #000;\n}\n.form-horizontal .main-checkbox{\n\tfloat: left;\n\twidth: 20px;\n\theight: 20px;\n\tbackground: #11a3fc;\n\tborder-radius: 50%;\n\tposition: relative;\n\tmargin: 5px 0 0 5px;\n\tborder: 1px solid #11a3fc;\n}\n.form-horizontal .main-checkbox label{\n\twidth: 20px;\n\theight: 20px;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tcursor: pointer;\n}\n.form-horizontal .main-checkbox label:after{\n\tcontent: \"\";\n\twidth: 10px;\n\theight: 5px;\n\tposition: absolute;\n\ttop: 5px;\n\tleft: 4px;\n\tborder: 3px solid #fff;\n\tborder-top: none;\n\tborder-right: none;\n\tbackground: transparent;\n\topacity: 0;\n\t-webkit-transform: rotate(-45deg);\n\ttransform: rotate(-45deg);\n}\n.form-horizontal .main-checkbox input[type=checkbox]{\n\tvisibility: hidden;\n}\n.form-horizontal .main-checkbox input[type=checkbox]:checked + label:after{\n\topacity: 1;\n}\n.form-horizontal .text{\n\tfloat: left;\n\tmargin-left: 7px;\n\tline-height: 20px;\n\tpadding-top: 5px;\n\ttext-transform: capitalize;\n}\n.form-horizontal .btn{\n\tfloat: right;\n\tfont-size: 14px;\n\tcolor: #fff;\n\tbackground: #00b4ef;\n\tborder-radius: 30px;\n\tpadding: 10px 25px;\n\tborder: none;\n\ttext-transform: capitalize;\n\ttransition: all 0.5s ease 0s;\n}\n@media only screen and (max-width: 479px){\n\t.form-horizontal .form-group{\n\t\tpadding: 0 25px;\n\t}\n\t.form-horizontal .form-group i{\n\t\tleft: 45px;\n\t}\n\t.form-horizontal .btn{\n\t\tpadding: 10px 20px;\n\t}\n}"
  },
  {
    "path": "src/main/webapp/static/bootstrap/js/bootstrap.js",
    "content": "/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under the MIT license\n */\n\nif (typeof jQuery === 'undefined') {\n  throw new Error('Bootstrap\\'s JavaScript requires jQuery')\n}\n\n+function ($) {\n  'use strict';\n  var version = $.fn.jquery.split(' ')[0].split('.')\n  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {\n    throw new Error('Bootstrap\\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')\n  }\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: transition.js v3.3.7\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n  // ============================================================\n\n  function transitionEnd() {\n    var el = document.createElement('bootstrap')\n\n    var transEndEventNames = {\n      WebkitTransition : 'webkitTransitionEnd',\n      MozTransition    : 'transitionend',\n      OTransition      : 'oTransitionEnd otransitionend',\n      transition       : 'transitionend'\n    }\n\n    for (var name in transEndEventNames) {\n      if (el.style[name] !== undefined) {\n        return { end: transEndEventNames[name] }\n      }\n    }\n\n    return false // explicit for ie8 (  ._.)\n  }\n\n  // http://blog.alexmaccaw.com/css-transitions\n  $.fn.emulateTransitionEnd = function (duration) {\n    var called = false\n    var $el = this\n    $(this).one('bsTransitionEnd', function () { called = true })\n    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n    setTimeout(callback, duration)\n    return this\n  }\n\n  $(function () {\n    $.support.transition = transitionEnd()\n\n    if (!$.support.transition) return\n\n    $.event.special.bsTransitionEnd = {\n      bindType: $.support.transition.end,\n      delegateType: $.support.transition.end,\n      handle: function (e) {\n        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n      }\n    }\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: alert.js v3.3.7\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // ALERT CLASS DEFINITION\n  // ======================\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n  var Alert   = function (el) {\n    $(el).on('click', dismiss, this.close)\n  }\n\n  Alert.VERSION = '3.3.7'\n\n  Alert.TRANSITION_DURATION = 150\n\n  Alert.prototype.close = function (e) {\n    var $this    = $(this)\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = $(selector === '#' ? [] : selector)\n\n    if (e) e.preventDefault()\n\n    if (!$parent.length) {\n      $parent = $this.closest('.alert')\n    }\n\n    $parent.trigger(e = $.Event('close.bs.alert'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      // detach from parent, fire event then clean up data\n      $parent.detach().trigger('closed.bs.alert').remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent\n        .one('bsTransitionEnd', removeElement)\n        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n      removeElement()\n  }\n\n\n  // ALERT PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.alert')\n\n      if (!data) $this.data('bs.alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.alert\n\n  $.fn.alert             = Plugin\n  $.fn.alert.Constructor = Alert\n\n\n  // ALERT NO CONFLICT\n  // =================\n\n  $.fn.alert.noConflict = function () {\n    $.fn.alert = old\n    return this\n  }\n\n\n  // ALERT DATA-API\n  // ==============\n\n  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: button.js v3.3.7\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // BUTTON PUBLIC CLASS DEFINITION\n  // ==============================\n\n  var Button = function (element, options) {\n    this.$element  = $(element)\n    this.options   = $.extend({}, Button.DEFAULTS, options)\n    this.isLoading = false\n  }\n\n  Button.VERSION  = '3.3.7'\n\n  Button.DEFAULTS = {\n    loadingText: 'loading...'\n  }\n\n  Button.prototype.setState = function (state) {\n    var d    = 'disabled'\n    var $el  = this.$element\n    var val  = $el.is('input') ? 'val' : 'html'\n    var data = $el.data()\n\n    state += 'Text'\n\n    if (data.resetText == null) $el.data('resetText', $el[val]())\n\n    // push to event loop to allow forms to submit\n    setTimeout($.proxy(function () {\n      $el[val](data[state] == null ? this.options[state] : data[state])\n\n      if (state == 'loadingText') {\n        this.isLoading = true\n        $el.addClass(d).attr(d, d).prop(d, true)\n      } else if (this.isLoading) {\n        this.isLoading = false\n        $el.removeClass(d).removeAttr(d).prop(d, false)\n      }\n    }, this), 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var changed = true\n    var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n\n    if ($parent.length) {\n      var $input = this.$element.find('input')\n      if ($input.prop('type') == 'radio') {\n        if ($input.prop('checked')) changed = false\n        $parent.find('.active').removeClass('active')\n        this.$element.addClass('active')\n      } else if ($input.prop('type') == 'checkbox') {\n        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false\n        this.$element.toggleClass('active')\n      }\n      $input.prop('checked', this.$element.hasClass('active'))\n      if (changed) $input.trigger('change')\n    } else {\n      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n      this.$element.toggleClass('active')\n    }\n  }\n\n\n  // BUTTON PLUGIN DEFINITION\n  // ========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.button')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  var old = $.fn.button\n\n  $.fn.button             = Plugin\n  $.fn.button.Constructor = Button\n\n\n  // BUTTON NO CONFLICT\n  // ==================\n\n  $.fn.button.noConflict = function () {\n    $.fn.button = old\n    return this\n  }\n\n\n  // BUTTON DATA-API\n  // ===============\n\n  $(document)\n    .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      var $btn = $(e.target).closest('.btn')\n      Plugin.call($btn, 'toggle')\n      if (!($(e.target).is('input[type=\"radio\"], input[type=\"checkbox\"]'))) {\n        // Prevent double click on radios, and the double selections (so cancellation) on checkboxes\n        e.preventDefault()\n        // The target component still receive the focus\n        if ($btn.is('input,button')) $btn.trigger('focus')\n        else $btn.find('input:visible,button:visible').first().trigger('focus')\n      }\n    })\n    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n    })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: carousel.js v3.3.7\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CAROUSEL CLASS DEFINITION\n  // =========================\n\n  var Carousel = function (element, options) {\n    this.$element    = $(element)\n    this.$indicators = this.$element.find('.carousel-indicators')\n    this.options     = options\n    this.paused      = null\n    this.sliding     = null\n    this.interval    = null\n    this.$active     = null\n    this.$items      = null\n\n    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n\n    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n  }\n\n  Carousel.VERSION  = '3.3.7'\n\n  Carousel.TRANSITION_DURATION = 600\n\n  Carousel.DEFAULTS = {\n    interval: 5000,\n    pause: 'hover',\n    wrap: true,\n    keyboard: true\n  }\n\n  Carousel.prototype.keydown = function (e) {\n    if (/input|textarea/i.test(e.target.tagName)) return\n    switch (e.which) {\n      case 37: this.prev(); break\n      case 39: this.next(); break\n      default: return\n    }\n\n    e.preventDefault()\n  }\n\n  Carousel.prototype.cycle = function (e) {\n    e || (this.paused = false)\n\n    this.interval && clearInterval(this.interval)\n\n    this.options.interval\n      && !this.paused\n      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n\n    return this\n  }\n\n  Carousel.prototype.getItemIndex = function (item) {\n    this.$items = item.parent().children('.item')\n    return this.$items.index(item || this.$active)\n  }\n\n  Carousel.prototype.getItemForDirection = function (direction, active) {\n    var activeIndex = this.getItemIndex(active)\n    var willWrap = (direction == 'prev' && activeIndex === 0)\n                || (direction == 'next' && activeIndex == (this.$items.length - 1))\n    if (willWrap && !this.options.wrap) return active\n    var delta = direction == 'prev' ? -1 : 1\n    var itemIndex = (activeIndex + delta) % this.$items.length\n    return this.$items.eq(itemIndex)\n  }\n\n  Carousel.prototype.to = function (pos) {\n    var that        = this\n    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n\n    if (pos > (this.$items.length - 1) || pos < 0) return\n\n    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n    if (activeIndex == pos) return this.pause().cycle()\n\n    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n  }\n\n  Carousel.prototype.pause = function (e) {\n    e || (this.paused = true)\n\n    if (this.$element.find('.next, .prev').length && $.support.transition) {\n      this.$element.trigger($.support.transition.end)\n      this.cycle(true)\n    }\n\n    this.interval = clearInterval(this.interval)\n\n    return this\n  }\n\n  Carousel.prototype.next = function () {\n    if (this.sliding) return\n    return this.slide('next')\n  }\n\n  Carousel.prototype.prev = function () {\n    if (this.sliding) return\n    return this.slide('prev')\n  }\n\n  Carousel.prototype.slide = function (type, next) {\n    var $active   = this.$element.find('.item.active')\n    var $next     = next || this.getItemForDirection(type, $active)\n    var isCycling = this.interval\n    var direction = type == 'next' ? 'left' : 'right'\n    var that      = this\n\n    if ($next.hasClass('active')) return (this.sliding = false)\n\n    var relatedTarget = $next[0]\n    var slideEvent = $.Event('slide.bs.carousel', {\n      relatedTarget: relatedTarget,\n      direction: direction\n    })\n    this.$element.trigger(slideEvent)\n    if (slideEvent.isDefaultPrevented()) return\n\n    this.sliding = true\n\n    isCycling && this.pause()\n\n    if (this.$indicators.length) {\n      this.$indicators.find('.active').removeClass('active')\n      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n      $nextIndicator && $nextIndicator.addClass('active')\n    }\n\n    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n    if ($.support.transition && this.$element.hasClass('slide')) {\n      $next.addClass(type)\n      $next[0].offsetWidth // force reflow\n      $active.addClass(direction)\n      $next.addClass(direction)\n      $active\n        .one('bsTransitionEnd', function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () {\n            that.$element.trigger(slidEvent)\n          }, 0)\n        })\n        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n    } else {\n      $active.removeClass('active')\n      $next.addClass('active')\n      this.sliding = false\n      this.$element.trigger(slidEvent)\n    }\n\n    isCycling && this.cycle()\n\n    return this\n  }\n\n\n  // CAROUSEL PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.carousel')\n      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n      var action  = typeof option == 'string' ? option : options.slide\n\n      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.pause().cycle()\n    })\n  }\n\n  var old = $.fn.carousel\n\n  $.fn.carousel             = Plugin\n  $.fn.carousel.Constructor = Carousel\n\n\n  // CAROUSEL NO CONFLICT\n  // ====================\n\n  $.fn.carousel.noConflict = function () {\n    $.fn.carousel = old\n    return this\n  }\n\n\n  // CAROUSEL DATA-API\n  // =================\n\n  var clickHandler = function (e) {\n    var href\n    var $this   = $(this)\n    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n    if (!$target.hasClass('carousel')) return\n    var options = $.extend({}, $target.data(), $this.data())\n    var slideIndex = $this.attr('data-slide-to')\n    if (slideIndex) options.interval = false\n\n    Plugin.call($target, options)\n\n    if (slideIndex) {\n      $target.data('bs.carousel').to(slideIndex)\n    }\n\n    e.preventDefault()\n  }\n\n  $(document)\n    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n\n  $(window).on('load', function () {\n    $('[data-ride=\"carousel\"]').each(function () {\n      var $carousel = $(this)\n      Plugin.call($carousel, $carousel.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: collapse.js v3.3.7\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n/* jshint latedef: false */\n\n+function ($) {\n  'use strict';\n\n  // COLLAPSE PUBLIC CLASS DEFINITION\n  // ================================\n\n  var Collapse = function (element, options) {\n    this.$element      = $(element)\n    this.options       = $.extend({}, Collapse.DEFAULTS, options)\n    this.$trigger      = $('[data-toggle=\"collapse\"][href=\"#' + element.id + '\"],' +\n                           '[data-toggle=\"collapse\"][data-target=\"#' + element.id + '\"]')\n    this.transitioning = null\n\n    if (this.options.parent) {\n      this.$parent = this.getParent()\n    } else {\n      this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n    }\n\n    if (this.options.toggle) this.toggle()\n  }\n\n  Collapse.VERSION  = '3.3.7'\n\n  Collapse.TRANSITION_DURATION = 350\n\n  Collapse.DEFAULTS = {\n    toggle: true\n  }\n\n  Collapse.prototype.dimension = function () {\n    var hasWidth = this.$element.hasClass('width')\n    return hasWidth ? 'width' : 'height'\n  }\n\n  Collapse.prototype.show = function () {\n    if (this.transitioning || this.$element.hasClass('in')) return\n\n    var activesData\n    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')\n\n    if (actives && actives.length) {\n      activesData = actives.data('bs.collapse')\n      if (activesData && activesData.transitioning) return\n    }\n\n    var startEvent = $.Event('show.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    if (actives && actives.length) {\n      Plugin.call(actives, 'hide')\n      activesData || actives.data('bs.collapse', null)\n    }\n\n    var dimension = this.dimension()\n\n    this.$element\n      .removeClass('collapse')\n      .addClass('collapsing')[dimension](0)\n      .attr('aria-expanded', true)\n\n    this.$trigger\n      .removeClass('collapsed')\n      .attr('aria-expanded', true)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse in')[dimension]('')\n      this.transitioning = 0\n      this.$element\n        .trigger('shown.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n\n    this.$element\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n  }\n\n  Collapse.prototype.hide = function () {\n    if (this.transitioning || !this.$element.hasClass('in')) return\n\n    var startEvent = $.Event('hide.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    var dimension = this.dimension()\n\n    this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n\n    this.$element\n      .addClass('collapsing')\n      .removeClass('collapse in')\n      .attr('aria-expanded', false)\n\n    this.$trigger\n      .addClass('collapsed')\n      .attr('aria-expanded', false)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.transitioning = 0\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse')\n        .trigger('hidden.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    this.$element\n      [dimension](0)\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n  }\n\n  Collapse.prototype.toggle = function () {\n    this[this.$element.hasClass('in') ? 'hide' : 'show']()\n  }\n\n  Collapse.prototype.getParent = function () {\n    return $(this.options.parent)\n      .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n      .each($.proxy(function (i, element) {\n        var $element = $(element)\n        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n      }, this))\n      .end()\n  }\n\n  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n    var isOpen = $element.hasClass('in')\n\n    $element.attr('aria-expanded', isOpen)\n    $trigger\n      .toggleClass('collapsed', !isOpen)\n      .attr('aria-expanded', isOpen)\n  }\n\n  function getTargetFromTrigger($trigger) {\n    var href\n    var target = $trigger.attr('data-target')\n      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n\n    return $(target)\n  }\n\n\n  // COLLAPSE PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.collapse')\n      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false\n      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.collapse\n\n  $.fn.collapse             = Plugin\n  $.fn.collapse.Constructor = Collapse\n\n\n  // COLLAPSE NO CONFLICT\n  // ====================\n\n  $.fn.collapse.noConflict = function () {\n    $.fn.collapse = old\n    return this\n  }\n\n\n  // COLLAPSE DATA-API\n  // =================\n\n  $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n    var $this   = $(this)\n\n    if (!$this.attr('data-target')) e.preventDefault()\n\n    var $target = getTargetFromTrigger($this)\n    var data    = $target.data('bs.collapse')\n    var option  = data ? 'toggle' : $this.data()\n\n    Plugin.call($target, option)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: dropdown.js v3.3.7\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // DROPDOWN CLASS DEFINITION\n  // =========================\n\n  var backdrop = '.dropdown-backdrop'\n  var toggle   = '[data-toggle=\"dropdown\"]'\n  var Dropdown = function (element) {\n    $(element).on('click.bs.dropdown', this.toggle)\n  }\n\n  Dropdown.VERSION = '3.3.7'\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = selector && $(selector)\n\n    return $parent && $parent.length ? $parent : $this.parent()\n  }\n\n  function clearMenus(e) {\n    if (e && e.which === 3) return\n    $(backdrop).remove()\n    $(toggle).each(function () {\n      var $this         = $(this)\n      var $parent       = getParent($this)\n      var relatedTarget = { relatedTarget: this }\n\n      if (!$parent.hasClass('open')) return\n\n      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return\n\n      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this.attr('aria-expanded', 'false')\n      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))\n    })\n  }\n\n  Dropdown.prototype.toggle = function (e) {\n    var $this = $(this)\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    clearMenus()\n\n    if (!isActive) {\n      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n        // if mobile we use a backdrop because click events don't delegate\n        $(document.createElement('div'))\n          .addClass('dropdown-backdrop')\n          .insertAfter($(this))\n          .on('click', clearMenus)\n      }\n\n      var relatedTarget = { relatedTarget: this }\n      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this\n        .trigger('focus')\n        .attr('aria-expanded', 'true')\n\n      $parent\n        .toggleClass('open')\n        .trigger($.Event('shown.bs.dropdown', relatedTarget))\n    }\n\n    return false\n  }\n\n  Dropdown.prototype.keydown = function (e) {\n    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n\n    var $this = $(this)\n\n    e.preventDefault()\n    e.stopPropagation()\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    if (!isActive && e.which != 27 || isActive && e.which == 27) {\n      if (e.which == 27) $parent.find(toggle).trigger('focus')\n      return $this.trigger('click')\n    }\n\n    var desc = ' li:not(.disabled):visible a'\n    var $items = $parent.find('.dropdown-menu' + desc)\n\n    if (!$items.length) return\n\n    var index = $items.index(e.target)\n\n    if (e.which == 38 && index > 0)                 index--         // up\n    if (e.which == 40 && index < $items.length - 1) index++         // down\n    if (!~index)                                    index = 0\n\n    $items.eq(index).trigger('focus')\n  }\n\n\n  // DROPDOWN PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.dropdown')\n\n      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.dropdown\n\n  $.fn.dropdown             = Plugin\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  // DROPDOWN NO CONFLICT\n  // ====================\n\n  $.fn.dropdown.noConflict = function () {\n    $.fn.dropdown = old\n    return this\n  }\n\n\n  // APPLY TO STANDARD DROPDOWN ELEMENTS\n  // ===================================\n\n  $(document)\n    .on('click.bs.dropdown.data-api', clearMenus)\n    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: modal.js v3.3.7\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // MODAL CLASS DEFINITION\n  // ======================\n\n  var Modal = function (element, options) {\n    this.options             = options\n    this.$body               = $(document.body)\n    this.$element            = $(element)\n    this.$dialog             = this.$element.find('.modal-dialog')\n    this.$backdrop           = null\n    this.isShown             = null\n    this.originalBodyPad     = null\n    this.scrollbarWidth      = 0\n    this.ignoreBackdropClick = false\n\n    if (this.options.remote) {\n      this.$element\n        .find('.modal-content')\n        .load(this.options.remote, $.proxy(function () {\n          this.$element.trigger('loaded.bs.modal')\n        }, this))\n    }\n  }\n\n  Modal.VERSION  = '3.3.7'\n\n  Modal.TRANSITION_DURATION = 300\n  Modal.BACKDROP_TRANSITION_DURATION = 150\n\n  Modal.DEFAULTS = {\n    backdrop: true,\n    keyboard: true,\n    show: true\n  }\n\n  Modal.prototype.toggle = function (_relatedTarget) {\n    return this.isShown ? this.hide() : this.show(_relatedTarget)\n  }\n\n  Modal.prototype.show = function (_relatedTarget) {\n    var that = this\n    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n\n    this.$element.trigger(e)\n\n    if (this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = true\n\n    this.checkScrollbar()\n    this.setScrollbar()\n    this.$body.addClass('modal-open')\n\n    this.escape()\n    this.resize()\n\n    this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n\n    this.$dialog.on('mousedown.dismiss.bs.modal', function () {\n      that.$element.one('mouseup.dismiss.bs.modal', function (e) {\n        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true\n      })\n    })\n\n    this.backdrop(function () {\n      var transition = $.support.transition && that.$element.hasClass('fade')\n\n      if (!that.$element.parent().length) {\n        that.$element.appendTo(that.$body) // don't move modals dom position\n      }\n\n      that.$element\n        .show()\n        .scrollTop(0)\n\n      that.adjustDialog()\n\n      if (transition) {\n        that.$element[0].offsetWidth // force reflow\n      }\n\n      that.$element.addClass('in')\n\n      that.enforceFocus()\n\n      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n\n      transition ?\n        that.$dialog // wait for modal to slide in\n          .one('bsTransitionEnd', function () {\n            that.$element.trigger('focus').trigger(e)\n          })\n          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n        that.$element.trigger('focus').trigger(e)\n    })\n  }\n\n  Modal.prototype.hide = function (e) {\n    if (e) e.preventDefault()\n\n    e = $.Event('hide.bs.modal')\n\n    this.$element.trigger(e)\n\n    if (!this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = false\n\n    this.escape()\n    this.resize()\n\n    $(document).off('focusin.bs.modal')\n\n    this.$element\n      .removeClass('in')\n      .off('click.dismiss.bs.modal')\n      .off('mouseup.dismiss.bs.modal')\n\n    this.$dialog.off('mousedown.dismiss.bs.modal')\n\n    $.support.transition && this.$element.hasClass('fade') ?\n      this.$element\n        .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n      this.hideModal()\n  }\n\n  Modal.prototype.enforceFocus = function () {\n    $(document)\n      .off('focusin.bs.modal') // guard against infinite focus loop\n      .on('focusin.bs.modal', $.proxy(function (e) {\n        if (document !== e.target &&\n            this.$element[0] !== e.target &&\n            !this.$element.has(e.target).length) {\n          this.$element.trigger('focus')\n        }\n      }, this))\n  }\n\n  Modal.prototype.escape = function () {\n    if (this.isShown && this.options.keyboard) {\n      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n        e.which == 27 && this.hide()\n      }, this))\n    } else if (!this.isShown) {\n      this.$element.off('keydown.dismiss.bs.modal')\n    }\n  }\n\n  Modal.prototype.resize = function () {\n    if (this.isShown) {\n      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n    } else {\n      $(window).off('resize.bs.modal')\n    }\n  }\n\n  Modal.prototype.hideModal = function () {\n    var that = this\n    this.$element.hide()\n    this.backdrop(function () {\n      that.$body.removeClass('modal-open')\n      that.resetAdjustments()\n      that.resetScrollbar()\n      that.$element.trigger('hidden.bs.modal')\n    })\n  }\n\n  Modal.prototype.removeBackdrop = function () {\n    this.$backdrop && this.$backdrop.remove()\n    this.$backdrop = null\n  }\n\n  Modal.prototype.backdrop = function (callback) {\n    var that = this\n    var animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n    if (this.isShown && this.options.backdrop) {\n      var doAnimate = $.support.transition && animate\n\n      this.$backdrop = $(document.createElement('div'))\n        .addClass('modal-backdrop ' + animate)\n        .appendTo(this.$body)\n\n      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {\n        if (this.ignoreBackdropClick) {\n          this.ignoreBackdropClick = false\n          return\n        }\n        if (e.target !== e.currentTarget) return\n        this.options.backdrop == 'static'\n          ? this.$element[0].focus()\n          : this.hide()\n      }, this))\n\n      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n      this.$backdrop.addClass('in')\n\n      if (!callback) return\n\n      doAnimate ?\n        this.$backdrop\n          .one('bsTransitionEnd', callback)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callback()\n\n    } else if (!this.isShown && this.$backdrop) {\n      this.$backdrop.removeClass('in')\n\n      var callbackRemove = function () {\n        that.removeBackdrop()\n        callback && callback()\n      }\n      $.support.transition && this.$element.hasClass('fade') ?\n        this.$backdrop\n          .one('bsTransitionEnd', callbackRemove)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callbackRemove()\n\n    } else if (callback) {\n      callback()\n    }\n  }\n\n  // these following methods are used to handle overflowing modals\n\n  Modal.prototype.handleUpdate = function () {\n    this.adjustDialog()\n  }\n\n  Modal.prototype.adjustDialog = function () {\n    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n\n    this.$element.css({\n      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n    })\n  }\n\n  Modal.prototype.resetAdjustments = function () {\n    this.$element.css({\n      paddingLeft: '',\n      paddingRight: ''\n    })\n  }\n\n  Modal.prototype.checkScrollbar = function () {\n    var fullWindowWidth = window.innerWidth\n    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8\n      var documentElementRect = document.documentElement.getBoundingClientRect()\n      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)\n    }\n    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth\n    this.scrollbarWidth = this.measureScrollbar()\n  }\n\n  Modal.prototype.setScrollbar = function () {\n    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n    this.originalBodyPad = document.body.style.paddingRight || ''\n    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n  }\n\n  Modal.prototype.resetScrollbar = function () {\n    this.$body.css('padding-right', this.originalBodyPad)\n  }\n\n  Modal.prototype.measureScrollbar = function () { // thx walsh\n    var scrollDiv = document.createElement('div')\n    scrollDiv.className = 'modal-scrollbar-measure'\n    this.$body.append(scrollDiv)\n    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n    this.$body[0].removeChild(scrollDiv)\n    return scrollbarWidth\n  }\n\n\n  // MODAL PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option, _relatedTarget) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.modal')\n      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option](_relatedTarget)\n      else if (options.show) data.show(_relatedTarget)\n    })\n  }\n\n  var old = $.fn.modal\n\n  $.fn.modal             = Plugin\n  $.fn.modal.Constructor = Modal\n\n\n  // MODAL NO CONFLICT\n  // =================\n\n  $.fn.modal.noConflict = function () {\n    $.fn.modal = old\n    return this\n  }\n\n\n  // MODAL DATA-API\n  // ==============\n\n  $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n    var $this   = $(this)\n    var href    = $this.attr('href')\n    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n    if ($this.is('a')) e.preventDefault()\n\n    $target.one('show.bs.modal', function (showEvent) {\n      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n      $target.one('hidden.bs.modal', function () {\n        $this.is(':visible') && $this.trigger('focus')\n      })\n    })\n    Plugin.call($target, option, this)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tooltip.js v3.3.7\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TOOLTIP PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Tooltip = function (element, options) {\n    this.type       = null\n    this.options    = null\n    this.enabled    = null\n    this.timeout    = null\n    this.hoverState = null\n    this.$element   = null\n    this.inState    = null\n\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.VERSION  = '3.3.7'\n\n  Tooltip.TRANSITION_DURATION = 150\n\n  Tooltip.DEFAULTS = {\n    animation: true,\n    placement: 'top',\n    selector: false,\n    template: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    container: false,\n    viewport: {\n      selector: 'body',\n      padding: 0\n    }\n  }\n\n  Tooltip.prototype.init = function (type, element, options) {\n    this.enabled   = true\n    this.type      = type\n    this.$element  = $(element)\n    this.options   = this.getOptions(options)\n    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))\n    this.inState   = { click: false, hover: false, focus: false }\n\n    if (this.$element[0] instanceof document.constructor && !this.options.selector) {\n      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')\n    }\n\n    var triggers = this.options.trigger.split(' ')\n\n    for (var i = triggers.length; i--;) {\n      var trigger = triggers[i]\n\n      if (trigger == 'click') {\n        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n      } else if (trigger != 'manual') {\n        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'\n        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n\n        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n      }\n    }\n\n    this.options.selector ?\n      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n      this.fixTitle()\n  }\n\n  Tooltip.prototype.getDefaults = function () {\n    return Tooltip.DEFAULTS\n  }\n\n  Tooltip.prototype.getOptions = function (options) {\n    options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n\n    if (options.delay && typeof options.delay == 'number') {\n      options.delay = {\n        show: options.delay,\n        hide: options.delay\n      }\n    }\n\n    return options\n  }\n\n  Tooltip.prototype.getDelegateOptions = function () {\n    var options  = {}\n    var defaults = this.getDefaults()\n\n    this._options && $.each(this._options, function (key, value) {\n      if (defaults[key] != value) options[key] = value\n    })\n\n    return options\n  }\n\n  Tooltip.prototype.enter = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    if (obj instanceof $.Event) {\n      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true\n    }\n\n    if (self.tip().hasClass('in') || self.hoverState == 'in') {\n      self.hoverState = 'in'\n      return\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'in'\n\n    if (!self.options.delay || !self.options.delay.show) return self.show()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'in') self.show()\n    }, self.options.delay.show)\n  }\n\n  Tooltip.prototype.isInStateTrue = function () {\n    for (var key in this.inState) {\n      if (this.inState[key]) return true\n    }\n\n    return false\n  }\n\n  Tooltip.prototype.leave = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    if (obj instanceof $.Event) {\n      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false\n    }\n\n    if (self.isInStateTrue()) return\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'out'\n\n    if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'out') self.hide()\n    }, self.options.delay.hide)\n  }\n\n  Tooltip.prototype.show = function () {\n    var e = $.Event('show.bs.' + this.type)\n\n    if (this.hasContent() && this.enabled) {\n      this.$element.trigger(e)\n\n      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n      if (e.isDefaultPrevented() || !inDom) return\n      var that = this\n\n      var $tip = this.tip()\n\n      var tipId = this.getUID(this.type)\n\n      this.setContent()\n      $tip.attr('id', tipId)\n      this.$element.attr('aria-describedby', tipId)\n\n      if (this.options.animation) $tip.addClass('fade')\n\n      var placement = typeof this.options.placement == 'function' ?\n        this.options.placement.call(this, $tip[0], this.$element[0]) :\n        this.options.placement\n\n      var autoToken = /\\s?auto?\\s?/i\n      var autoPlace = autoToken.test(placement)\n      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n\n      $tip\n        .detach()\n        .css({ top: 0, left: 0, display: 'block' })\n        .addClass(placement)\n        .data('bs.' + this.type, this)\n\n      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n      this.$element.trigger('inserted.bs.' + this.type)\n\n      var pos          = this.getPosition()\n      var actualWidth  = $tip[0].offsetWidth\n      var actualHeight = $tip[0].offsetHeight\n\n      if (autoPlace) {\n        var orgPlacement = placement\n        var viewportDim = this.getPosition(this.$viewport)\n\n        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :\n                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :\n                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :\n                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :\n                    placement\n\n        $tip\n          .removeClass(orgPlacement)\n          .addClass(placement)\n      }\n\n      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n\n      this.applyPlacement(calculatedOffset, placement)\n\n      var complete = function () {\n        var prevHoverState = that.hoverState\n        that.$element.trigger('shown.bs.' + that.type)\n        that.hoverState = null\n\n        if (prevHoverState == 'out') that.leave(that)\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        $tip\n          .one('bsTransitionEnd', complete)\n          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n        complete()\n    }\n  }\n\n  Tooltip.prototype.applyPlacement = function (offset, placement) {\n    var $tip   = this.tip()\n    var width  = $tip[0].offsetWidth\n    var height = $tip[0].offsetHeight\n\n    // manually read margins because getBoundingClientRect includes difference\n    var marginTop = parseInt($tip.css('margin-top'), 10)\n    var marginLeft = parseInt($tip.css('margin-left'), 10)\n\n    // we must check for NaN for ie 8/9\n    if (isNaN(marginTop))  marginTop  = 0\n    if (isNaN(marginLeft)) marginLeft = 0\n\n    offset.top  += marginTop\n    offset.left += marginLeft\n\n    // $.fn.offset doesn't round pixel values\n    // so we use setOffset directly with our own function B-0\n    $.offset.setOffset($tip[0], $.extend({\n      using: function (props) {\n        $tip.css({\n          top: Math.round(props.top),\n          left: Math.round(props.left)\n        })\n      }\n    }, offset), 0)\n\n    $tip.addClass('in')\n\n    // check to see if placing tip in new offset caused the tip to resize itself\n    var actualWidth  = $tip[0].offsetWidth\n    var actualHeight = $tip[0].offsetHeight\n\n    if (placement == 'top' && actualHeight != height) {\n      offset.top = offset.top + height - actualHeight\n    }\n\n    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n\n    if (delta.left) offset.left += delta.left\n    else offset.top += delta.top\n\n    var isVertical          = /top|bottom/.test(placement)\n    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n\n    $tip.offset(offset)\n    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n  }\n\n  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {\n    this.arrow()\n      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n      .css(isVertical ? 'top' : 'left', '')\n  }\n\n  Tooltip.prototype.setContent = function () {\n    var $tip  = this.tip()\n    var title = this.getTitle()\n\n    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n    $tip.removeClass('fade in top bottom left right')\n  }\n\n  Tooltip.prototype.hide = function (callback) {\n    var that = this\n    var $tip = $(this.$tip)\n    var e    = $.Event('hide.bs.' + this.type)\n\n    function complete() {\n      if (that.hoverState != 'in') $tip.detach()\n      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.\n        that.$element\n          .removeAttr('aria-describedby')\n          .trigger('hidden.bs.' + that.type)\n      }\n      callback && callback()\n    }\n\n    this.$element.trigger(e)\n\n    if (e.isDefaultPrevented()) return\n\n    $tip.removeClass('in')\n\n    $.support.transition && $tip.hasClass('fade') ?\n      $tip\n        .one('bsTransitionEnd', complete)\n        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n      complete()\n\n    this.hoverState = null\n\n    return this\n  }\n\n  Tooltip.prototype.fixTitle = function () {\n    var $e = this.$element\n    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {\n      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n    }\n  }\n\n  Tooltip.prototype.hasContent = function () {\n    return this.getTitle()\n  }\n\n  Tooltip.prototype.getPosition = function ($element) {\n    $element   = $element || this.$element\n\n    var el     = $element[0]\n    var isBody = el.tagName == 'BODY'\n\n    var elRect    = el.getBoundingClientRect()\n    if (elRect.width == null) {\n      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n    }\n    var isSvg = window.SVGElement && el instanceof window.SVGElement\n    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.\n    // See https://github.com/twbs/bootstrap/issues/20280\n    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())\n    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n\n    return $.extend({}, elRect, scroll, outerDims, elOffset)\n  }\n\n  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :\n           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :\n           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }\n\n  }\n\n  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n    var delta = { top: 0, left: 0 }\n    if (!this.$viewport) return delta\n\n    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n    var viewportDimensions = this.getPosition(this.$viewport)\n\n    if (/right|left/.test(placement)) {\n      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll\n      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n      if (topEdgeOffset < viewportDimensions.top) { // top overflow\n        delta.top = viewportDimensions.top - topEdgeOffset\n      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n      }\n    } else {\n      var leftEdgeOffset  = pos.left - viewportPadding\n      var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n      if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n        delta.left = viewportDimensions.left - leftEdgeOffset\n      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n      }\n    }\n\n    return delta\n  }\n\n  Tooltip.prototype.getTitle = function () {\n    var title\n    var $e = this.$element\n    var o  = this.options\n\n    title = $e.attr('data-original-title')\n      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n    return title\n  }\n\n  Tooltip.prototype.getUID = function (prefix) {\n    do prefix += ~~(Math.random() * 1000000)\n    while (document.getElementById(prefix))\n    return prefix\n  }\n\n  Tooltip.prototype.tip = function () {\n    if (!this.$tip) {\n      this.$tip = $(this.options.template)\n      if (this.$tip.length != 1) {\n        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')\n      }\n    }\n    return this.$tip\n  }\n\n  Tooltip.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n  }\n\n  Tooltip.prototype.enable = function () {\n    this.enabled = true\n  }\n\n  Tooltip.prototype.disable = function () {\n    this.enabled = false\n  }\n\n  Tooltip.prototype.toggleEnabled = function () {\n    this.enabled = !this.enabled\n  }\n\n  Tooltip.prototype.toggle = function (e) {\n    var self = this\n    if (e) {\n      self = $(e.currentTarget).data('bs.' + this.type)\n      if (!self) {\n        self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n        $(e.currentTarget).data('bs.' + this.type, self)\n      }\n    }\n\n    if (e) {\n      self.inState.click = !self.inState.click\n      if (self.isInStateTrue()) self.enter(self)\n      else self.leave(self)\n    } else {\n      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n    }\n  }\n\n  Tooltip.prototype.destroy = function () {\n    var that = this\n    clearTimeout(this.timeout)\n    this.hide(function () {\n      that.$element.off('.' + that.type).removeData('bs.' + that.type)\n      if (that.$tip) {\n        that.$tip.detach()\n      }\n      that.$tip = null\n      that.$arrow = null\n      that.$viewport = null\n      that.$element = null\n    })\n  }\n\n\n  // TOOLTIP PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.tooltip')\n      var options = typeof option == 'object' && option\n\n      if (!data && /destroy|hide/.test(option)) return\n      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tooltip\n\n  $.fn.tooltip             = Plugin\n  $.fn.tooltip.Constructor = Tooltip\n\n\n  // TOOLTIP NO CONFLICT\n  // ===================\n\n  $.fn.tooltip.noConflict = function () {\n    $.fn.tooltip = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: popover.js v3.3.7\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // POPOVER PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n\n  Popover.VERSION  = '3.3.7'\n\n  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n  })\n\n\n  // NOTE: POPOVER EXTENDS tooltip.js\n  // ================================\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n\n  Popover.prototype.constructor = Popover\n\n  Popover.prototype.getDefaults = function () {\n    return Popover.DEFAULTS\n  }\n\n  Popover.prototype.setContent = function () {\n    var $tip    = this.tip()\n    var title   = this.getTitle()\n    var content = this.getContent()\n\n    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n    ](content)\n\n    $tip.removeClass('fade top bottom left right in')\n\n    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n    // this manually by checking the contents.\n    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n  }\n\n  Popover.prototype.hasContent = function () {\n    return this.getTitle() || this.getContent()\n  }\n\n  Popover.prototype.getContent = function () {\n    var $e = this.$element\n    var o  = this.options\n\n    return $e.attr('data-content')\n      || (typeof o.content == 'function' ?\n            o.content.call($e[0]) :\n            o.content)\n  }\n\n  Popover.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n  }\n\n\n  // POPOVER PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.popover')\n      var options = typeof option == 'object' && option\n\n      if (!data && /destroy|hide/.test(option)) return\n      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.popover\n\n  $.fn.popover             = Plugin\n  $.fn.popover.Constructor = Popover\n\n\n  // POPOVER NO CONFLICT\n  // ===================\n\n  $.fn.popover.noConflict = function () {\n    $.fn.popover = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.7\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // SCROLLSPY CLASS DEFINITION\n  // ==========================\n\n  function ScrollSpy(element, options) {\n    this.$body          = $(document.body)\n    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)\n    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)\n    this.selector       = (this.options.target || '') + ' .nav li > a'\n    this.offsets        = []\n    this.targets        = []\n    this.activeTarget   = null\n    this.scrollHeight   = 0\n\n    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.VERSION  = '3.3.7'\n\n  ScrollSpy.DEFAULTS = {\n    offset: 10\n  }\n\n  ScrollSpy.prototype.getScrollHeight = function () {\n    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n  }\n\n  ScrollSpy.prototype.refresh = function () {\n    var that          = this\n    var offsetMethod  = 'offset'\n    var offsetBase    = 0\n\n    this.offsets      = []\n    this.targets      = []\n    this.scrollHeight = this.getScrollHeight()\n\n    if (!$.isWindow(this.$scrollElement[0])) {\n      offsetMethod = 'position'\n      offsetBase   = this.$scrollElement.scrollTop()\n    }\n\n    this.$body\n      .find(this.selector)\n      .map(function () {\n        var $el   = $(this)\n        var href  = $el.data('target') || $el.attr('href')\n        var $href = /^#./.test(href) && $(href)\n\n        return ($href\n          && $href.length\n          && $href.is(':visible')\n          && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n      })\n      .sort(function (a, b) { return a[0] - b[0] })\n      .each(function () {\n        that.offsets.push(this[0])\n        that.targets.push(this[1])\n      })\n  }\n\n  ScrollSpy.prototype.process = function () {\n    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset\n    var scrollHeight = this.getScrollHeight()\n    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()\n    var offsets      = this.offsets\n    var targets      = this.targets\n    var activeTarget = this.activeTarget\n    var i\n\n    if (this.scrollHeight != scrollHeight) {\n      this.refresh()\n    }\n\n    if (scrollTop >= maxScroll) {\n      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n    }\n\n    if (activeTarget && scrollTop < offsets[0]) {\n      this.activeTarget = null\n      return this.clear()\n    }\n\n    for (i = offsets.length; i--;) {\n      activeTarget != targets[i]\n        && scrollTop >= offsets[i]\n        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])\n        && this.activate(targets[i])\n    }\n  }\n\n  ScrollSpy.prototype.activate = function (target) {\n    this.activeTarget = target\n\n    this.clear()\n\n    var selector = this.selector +\n      '[data-target=\"' + target + '\"],' +\n      this.selector + '[href=\"' + target + '\"]'\n\n    var active = $(selector)\n      .parents('li')\n      .addClass('active')\n\n    if (active.parent('.dropdown-menu').length) {\n      active = active\n        .closest('li.dropdown')\n        .addClass('active')\n    }\n\n    active.trigger('activate.bs.scrollspy')\n  }\n\n  ScrollSpy.prototype.clear = function () {\n    $(this.selector)\n      .parentsUntil(this.options.target, '.active')\n      .removeClass('active')\n  }\n\n\n  // SCROLLSPY PLUGIN DEFINITION\n  // ===========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.scrollspy')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.scrollspy\n\n  $.fn.scrollspy             = Plugin\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n\n  // SCROLLSPY NO CONFLICT\n  // =====================\n\n  $.fn.scrollspy.noConflict = function () {\n    $.fn.scrollspy = old\n    return this\n  }\n\n\n  // SCROLLSPY DATA-API\n  // ==================\n\n  $(window).on('load.bs.scrollspy.data-api', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      Plugin.call($spy, $spy.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tab.js v3.3.7\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TAB CLASS DEFINITION\n  // ====================\n\n  var Tab = function (element) {\n    // jscs:disable requireDollarBeforejQueryAssignment\n    this.element = $(element)\n    // jscs:enable requireDollarBeforejQueryAssignment\n  }\n\n  Tab.VERSION = '3.3.7'\n\n  Tab.TRANSITION_DURATION = 150\n\n  Tab.prototype.show = function () {\n    var $this    = this.element\n    var $ul      = $this.closest('ul:not(.dropdown-menu)')\n    var selector = $this.data('target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    if ($this.parent('li').hasClass('active')) return\n\n    var $previous = $ul.find('.active:last a')\n    var hideEvent = $.Event('hide.bs.tab', {\n      relatedTarget: $this[0]\n    })\n    var showEvent = $.Event('show.bs.tab', {\n      relatedTarget: $previous[0]\n    })\n\n    $previous.trigger(hideEvent)\n    $this.trigger(showEvent)\n\n    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n\n    var $target = $(selector)\n\n    this.activate($this.closest('li'), $ul)\n    this.activate($target, $target.parent(), function () {\n      $previous.trigger({\n        type: 'hidden.bs.tab',\n        relatedTarget: $this[0]\n      })\n      $this.trigger({\n        type: 'shown.bs.tab',\n        relatedTarget: $previous[0]\n      })\n    })\n  }\n\n  Tab.prototype.activate = function (element, container, callback) {\n    var $active    = container.find('> .active')\n    var transition = callback\n      && $.support.transition\n      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)\n\n    function next() {\n      $active\n        .removeClass('active')\n        .find('> .dropdown-menu > .active')\n          .removeClass('active')\n        .end()\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', false)\n\n      element\n        .addClass('active')\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', true)\n\n      if (transition) {\n        element[0].offsetWidth // reflow for transition\n        element.addClass('in')\n      } else {\n        element.removeClass('fade')\n      }\n\n      if (element.parent('.dropdown-menu').length) {\n        element\n          .closest('li.dropdown')\n            .addClass('active')\n          .end()\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', true)\n      }\n\n      callback && callback()\n    }\n\n    $active.length && transition ?\n      $active\n        .one('bsTransitionEnd', next)\n        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n      next()\n\n    $active.removeClass('in')\n  }\n\n\n  // TAB PLUGIN DEFINITION\n  // =====================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.tab')\n\n      if (!data) $this.data('bs.tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tab\n\n  $.fn.tab             = Plugin\n  $.fn.tab.Constructor = Tab\n\n\n  // TAB NO CONFLICT\n  // ===============\n\n  $.fn.tab.noConflict = function () {\n    $.fn.tab = old\n    return this\n  }\n\n\n  // TAB DATA-API\n  // ============\n\n  var clickHandler = function (e) {\n    e.preventDefault()\n    Plugin.call($(this), 'show')\n  }\n\n  $(document)\n    .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n    .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: affix.js v3.3.7\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // AFFIX CLASS DEFINITION\n  // ======================\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, Affix.DEFAULTS, options)\n\n    this.$target = $(this.options.target)\n      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))\n\n    this.$element     = $(element)\n    this.affixed      = null\n    this.unpin        = null\n    this.pinnedOffset = null\n\n    this.checkPosition()\n  }\n\n  Affix.VERSION  = '3.3.7'\n\n  Affix.RESET    = 'affix affix-top affix-bottom'\n\n  Affix.DEFAULTS = {\n    offset: 0,\n    target: window\n  }\n\n  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n    var scrollTop    = this.$target.scrollTop()\n    var position     = this.$element.offset()\n    var targetHeight = this.$target.height()\n\n    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n\n    if (this.affixed == 'bottom') {\n      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n    }\n\n    var initializing   = this.affixed == null\n    var colliderTop    = initializing ? scrollTop : position.top\n    var colliderHeight = initializing ? targetHeight : height\n\n    if (offsetTop != null && scrollTop <= offsetTop) return 'top'\n    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n\n    return false\n  }\n\n  Affix.prototype.getPinnedOffset = function () {\n    if (this.pinnedOffset) return this.pinnedOffset\n    this.$element.removeClass(Affix.RESET).addClass('affix')\n    var scrollTop = this.$target.scrollTop()\n    var position  = this.$element.offset()\n    return (this.pinnedOffset = position.top - scrollTop)\n  }\n\n  Affix.prototype.checkPositionWithEventLoop = function () {\n    setTimeout($.proxy(this.checkPosition, this), 1)\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var height       = this.$element.height()\n    var offset       = this.options.offset\n    var offsetTop    = offset.top\n    var offsetBottom = offset.bottom\n    var scrollHeight = Math.max($(document).height(), $(document.body).height())\n\n    if (typeof offset != 'object')         offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n\n    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n\n    if (this.affixed != affix) {\n      if (this.unpin != null) this.$element.css('top', '')\n\n      var affixType = 'affix' + (affix ? '-' + affix : '')\n      var e         = $.Event(affixType + '.bs.affix')\n\n      this.$element.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      this.affixed = affix\n      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n\n      this.$element\n        .removeClass(Affix.RESET)\n        .addClass(affixType)\n        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n    }\n\n    if (affix == 'bottom') {\n      this.$element.offset({\n        top: scrollHeight - height - offsetBottom\n      })\n    }\n  }\n\n\n  // AFFIX PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.affix')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.affix\n\n  $.fn.affix             = Plugin\n  $.fn.affix.Constructor = Affix\n\n\n  // AFFIX NO CONFLICT\n  // =================\n\n  $.fn.affix.noConflict = function () {\n    $.fn.affix = old\n    return this\n  }\n\n\n  // AFFIX DATA-API\n  // ==============\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n      var data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n      if (data.offsetTop    != null) data.offset.top    = data.offsetTop\n\n      Plugin.call($spy, data)\n    })\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "src/main/webapp/static/bootstrap/js/npm.js",
    "content": "// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\nrequire('../../js/transition.js')\nrequire('../../js/alert.js')\nrequire('../../js/button.js')\nrequire('../../js/carousel.js')\nrequire('../../js/collapse.js')\nrequire('../../js/dropdown.js')\nrequire('../../js/modal.js')\nrequire('../../js/tooltip.js')\nrequire('../../js/popover.js')\nrequire('../../js/scrollspy.js')\nrequire('../../js/tab.js')\nrequire('../../js/affix.js')"
  },
  {
    "path": "src/main/webapp/static/css/buySeat.css",
    "content": ".container{\n    display: block;\n    margin-bottom: 100px;\n    padding: 0;\n}\n.container .order-progress-bar{\n    height: 60px;\n    width: 100%;\n    margin: 40px 0;\n    text-align: center;\n}\n.container .order-progress-bar .step{\n    float: left;\n    width: 25%;\n}\n.container .order-progress-bar .step .step-num{\n    color: #fff;\n    font-size: 12px;\n    display: inline-block;\n    width: 16px;\n    height: 16px;\n    line-height: 16px;\n    border-radius: 10px;\n    text-align: center;\n    background-color: #ffd8d7;\n    position: relative;\n    top: 10px;\n}\n.container .order-progress-bar .first .bar{\n    border-left-color: transparent !important;\n}\n.container .order-progress-bar .last .bar{\n    border-right-color: transparent !important;\n}\n.container .order-progress-bar .step .bar{\n    width: 0;\n    height: 4px;\n    border-left: 150px solid #ffd8d7;\n    border-right: 150px solid #ffd8d7;\n}\n.container .order-progress-bar .done .step-num{\n    background-color: #f03d37;\n}\n.container .order-progress-bar .done .bar{\n    border-left: 150px solid #f03d37;\n    border-right: 150px solid #f03d37;\n}\n.container .order-progress-bar .step .step-next{\n    font-size: 14px;\n    color: #999;\n    display: inline-block;\n    margin-top: 10px;\n}\n\n\n\n\n.main{\n    width: 100%;\n    border: 1px solid #e5e5e5;\n    font-size: 0;\n    min-height: 600px;\n}\n.main .hall{\n    width: 770px;\n    display: inline-block;\n    vertical-align: top;\n}\n.main .hall .seat-example{\n    margin: 30px 0 30px 118px;\n}\n.main .hall .seat-example .example{\n    display: inline-block;\n    font-size: 16px;\n    color: #666;\n    height: 26px;\n    line-height: 26px;\n    padding-left: 38px;\n    background-repeat: no-repeat;\n    margin-right: 50px;\n}\n.main .hall .seat-example .selectable-example{\n    background-image: url(\"../images/selectable_seat.JPG\");\n}\n.main .hall .seat-example .sold-example{\n    background-image: url(\"../images/sold_seat.JPG\");\n}\n.main .hall .seat-example .selected-example{\n    background-image: url(\"../images/selected_seat.JPG\");\n}\n.main .hall .seat-example .couple-example{\n    padding-left: 77px;\n    background-image: url(\"../images/couple_seat.JPG\");\n}\n.main .hall .seats-block{\n    font-size: 0;\n    overflow: hidden;\n    margin-left: 20px;\n    white-space: nowrap;\n}\n.main .hall .seats-block .row-id-container{\n    width: 20px;\n    float: left;\n    margin-top: 112px;\n    white-space: normal;\n}\n.main .hall .seats-block .row-id-container .row-id{\n    font-size: 16px;\n    color: #999;\n    margin-right: 40px;\n    margin-bottom: 10px;\n    display: inline-block;\n    width: 20px;\n    height: 26px;\n    line-height: 29px;\n    text-align: center;\n}\n.main .hall .seats-block .seats-container{\n    margin-left: 50px;\n    overflow: auto;\n    position: relative;\n    padding-top: 112px;\n}\n.main .hall .seats-block .seats-container .screen-container{\n    display: inline-block;\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    z-index: -1;\n}\n.main .hall .seats-block .seats-container .screen-container .screen{\n    width: 550px;\n    padding-top: 50px;\n    text-align: center;\n    font-size: 16px;\n    color: #666;\n    background: url(\"../images/screen.JPG\");\n    background-repeat: no-repeat;\n    position: relative;\n    margin-bottom: 40px\n\n}\n.main .hall .seats-block .seats-container .screen-container .c-screen-line {\n    width: 0;\n    border-left: 1px dashed #e5e5e5;\n    position: absolute;\n    top: 90px;\n    bottom: 0;\n    left: 50%;\n}\n.main .hall .seats-block .seats-wrapper{\n    display: inline-block;\n    min-width: 550px;\n}\n.main .hall .seats-block .seats-wrapper .row{\n    white-space: nowrap;\n    margin-bottom: 10px;\n    text-align: center;\n}\n.main .hall .seats-block .seats-wrapper .row .seat{\n    display: inline-block;\n    font-size: 0;\n    width: 30px;\n    height: 26px;\n    margin: 0 5px;\n    background: url(../images/selectable_seat.JPG) no-repeat;\n    background-position: 0 1px;\n}\n.main .hall .seats-block .seats-wrapper .row .empty{\n    background-image: none;\n}\n.main .hall .seats-block .seats-wrapper .row .selectable{\n    background: url(../images/selectable_seat.JPG) no-repeat;\n}\n.main .hall .seats-block .seats-wrapper .row .selected{\n    background: url(../images/selected_seat.JPG) no-repeat;\n}\n.main .hall .seats-block .seats-wrapper .row .sold{\n    background: url(../images/sold_seat.JPG) no-repeat;\n    pointer-events: none;\n}\n\n\n\n\n\n.main .side{\n    width: 368px;\n    background-color: #f9f9f9;\n    padding: 20px;\n    display: inline-block;\n    min-height: 650px;\n}\n.main .side .poster{\n    width: 115px;\n    height: 158px;\n    border: 2px solid #fff;\n    -webkit-box-shadow: 0 2px 7px 0 hsla(0,0%,53%,.5);\n    box-shadow: 0 2px 7px 0 hsla(0,0%,53%,.5);\n    float: left;\n}\n.main .side .poster img{\n    width: 100%;\n    height: 100%;\n}\n.main .side .content{\n    margin-left: 140px;\n}\n.main .side .content .name{\n    font-size: 20px;\n    font-weight: 700;\n    color: #333;\n    margin: 0 0 14px;\n}\n.main .side .content .text-ellipsis{\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n}\n.main .side .content .info-item{\n    font-size: 12px;\n    color: #999;\n    margin-bottom: 4px\n}\n.main .side .content .info-item .value{\n    color: #151515;\n    margin-left: 2px;\n}\n.main .side .show-info{\n    margin-top: 20px;\n}\n.main .side .show-info .info-item{\n    margin-bottom: 9px;\n    color: #999;\n}\n.main .side .show-info .info-item span{\n    display: inline-block;\n    vertical-align: top;\n    font-size: 14px;\n}\n.main .side .show-info .info-item .value{\n    width: 85%;\n    color: #151515;\n    margin-left: 2px;\n}\n.main .side .show-info .info-item .screen{\n    color: #f03d37;\n}\n.main .side .ticket-info{\n    padding: 20px 0 10px;\n    border-top: 1px dashed #e5e5e5;\n    border-bottom: 1px dashed #e5e5e5;\n}\n.main .side .ticket-info .no-ticket{\n    font-size: 14px;\n    color: #999;\n    margin: 0 0 20px;\n}\n.main .side .ticket-info .has-ticket .text{\n    font-size: 14px;\n    color: #999;\n    float: left;\n}\n.main .side .ticket-info .has-ticket .ticket-container{\n    margin-left: 42px;\n    margin-bottom: 20px;\n    position: relative;\n    top: -5px;\n}\n.main .side .ticket-info .has-ticket .ticket-container .ticket{\n    cursor: default;\n    position: relative;\n    font-size: 12px;\n    color: #f03d37;\n    display: inline-block;\n    width: 60px;\n    height: 30px;\n    line-height: 30px;\n    text-align: center;\n    margin: 0 12px 10px 0;\n    background: url(../images/ticket.JPG) no-repeat;\n}\n.main .side .ticket-info .total-price{\n    font-size: 14px;\n    color: #333;\n}\n.main .side .confirm-order{\n    padding: 20px 0;\n    text-align: center;\n}\n.main .side .confirm-order .email{\n    color: #999;\n    font-size: 14px;\n}\n.main .side .confirm-order .email .email-num{\n    color: #151515;\n}\n.main .side .confirm-order .confirm-btn{\n    cursor: pointer;\n    width: 260px;\n    height: 42px;\n    line-height: 42px;\n    text-align: center;\n    font-size: 16px;\n    color: #fff;\n    border-radius: 21px;\n    position: relative;\n    left: 50%;\n    margin: 38px 0 0 -130px;\n    background-color: #f03d37;\n    -webkit-box-shadow: 0 2px 10px -2px #f03d37;\n    box-shadow: 0 2px 10px -2px #f03d37;\n}\n.main .side .confirm-order .disable{\n    cursor: default;\n    background-color: #dedede;\n    box-shadow: none;\n    pointer-events: none;\n}\n"
  },
  {
    "path": "src/main/webapp/static/css/buyTickets.css",
    "content": "﻿.banner2 .wrapper {\n  \t\t/*background: #000;*/\n\t    width: 1200px;\n\t    margin: 0 auto;\n\t    height: 376px;\n\t    position: relative;\n\t}\t\n  \t.banner2 {\n\t    width: 100%;\n\t    min-width: 1200px;\n\t    background: #392f59 url(\"../images/banner.png\") no-repeat 50%;\n\t}\n\t.banner2 .wrapper .celeInfo-left {\n\t    width: 300px;\n\t    float: left;\n\t    position: relative;\n\t    top: 70px;\n\t    overflow: hidden;\n\t    z-index: 9;\n\t}\n  \t.celeInfo-left .avatar-shadow .avatar {\n\t    border: 4px solid #fff;\n\t    height: 322px;\n\t    width: 232px;\n\t}\n\t.celeInfo-left .avatar-shadow, .cinema-left .avatar-shadow {\n\t    position: relative;\n\t    margin: 0 30px;\n\t    width: 240px;\n\t    height: 330px;\n\t    padding-bottom: 40px;\n\t    background: url(\"../images/gray.jpg\") no-repeat bottom;\n\t}\n\t.banner2 .wrapper .celeInfo-right {\n\t\theight: 100%;\n\t    position: relative;\n\t    margin-right: 30px;\n\t    margin-left: 300px;\n\t    margin-top: 70px;\n\t}\n\t.movie-brief-container {\n\t    position: absolute;\n\t    top: 73px;\n\t    color: #fff;\n\t    font-size: 14px;\n\t    z-index: 1;\n\t}\n\t.movie-brief-container .name {\n\t    width: 900px;\n\t    margin-top: 0;\n\t    font-size: 26px;\n\t    line-height: 32px;\n\t    font-weight: 700;\n\t    margin-bottom: 0;\n\t    overflow: hidden;\n\t    text-overflow: ellipsis;\n\t    display: -webkit-box;\n\t    -webkit-line-clamp: 2;\n\t    -webkit-box-orient: vertical;\n\t    max-height: 64px;\n\t}\n\t.movie-brief-container .ename {\n\t    width: 340px;\n\t    font-size: 18px;\n\t    line-height: 1.3;\n\t    margin-bottom: 14px;\n\t}\n\t.banner2 li, .banner2 p, .banner2 ul {\n\t    margin: 0;\n\t    padding: 0;\n\t    list-style: none;\n\t    line-height: 1;\n\t}\n\t.movie-brief-container ul li {\n\t    margin: 12px 0;\n\t    line-height: 100%;\n\t}\n\t.action-buyBtn {\n\t    position: absolute;\n\t    bottom: 20px;\n\t}\n\t.action-buyBtn .action a {\n\t    cursor: pointer;\n\t    float: left;\n\t    display: block;\n\t    width: 120px;\n\t    height: 35px;\n\t    background-color: #756189;\n\t    margin-right: 10px;\n\t    padding-top: 11px;\n\t    text-align: center;\n\t    font-size: 14px;\n\t    line-height: 16px;\n\t    color: #fff;\n\t    border-radius: 2px;\n\t}\n\t.action-buyBtn .action i.icon {\n\t    display: inline-block;\n\t    vertical-align: middle;\n\t    margin-top: -2px;\n\t    margin-right: 2px;\n\t    width: 20px;\n\t    height: 20px;\n\t}\n\t.action-buyBtn .action .wish i.wish-icon {\n    \tbackground: url(\"../images/heart.jpg\");\n\t}\n\t.action-buyBtn .action .score-btn i.score-btn-icon {\n    \tbackground: url(\"../images/star.jpg\");\n\t}\n\t.btn {\n\t    display: inline-block;\n\t    padding: 2px 15px;\n\t    line-height: 25px;\n\t    font-size: 15px;\n\t    color: #fff;\n\t    background-color: #df2d2d;\n\t}\n\t.action-buyBtn .btn.buy {\n\t    margin-top: 10px;\n\t    width: 250px;\n\t    height: 40px;\n\t    font-size: 16px;\n\t    line-height: 40px;\n\t    text-align: center;\n\t    border-radius: 2px;\n\t\tpadding: 0;\n\t\tcolor: #ddd;\n\t}\n\t.action-buyBtn .btn.buy:hover {\n\t    color: #fff;\n\t}\n\t.movie-stats-container {\n\t    position: absolute;\n\t    top: 158px;\n\t    left: 342px;\n\t}\n\t.movie-stats-container .movie-index {\n\t    margin-bottom: 16px;\n\t    color: #fff;\n\t}\n\t.movie-stats-container .movie-index .movie-index-title {\n\t    font-size: 12px;\n\t    margin-bottom: 8px;\n\t}\n\t.movie-stats-container .movie-index .movie-index-content {\n    \toverflow: hidden;\n\t}\n\t.movie-stats-container .movie-index .movie-index-content .index-left {\n    \tfloat: left;\n\t}\n\t.movie-stats-container .movie-index .movie-index-content .info-num {\n\t    font-size: 30px;\n\t    color: #ffc600;\n\t    height: 30px;\n\t    line-height: 30px;\n\t}\n\t.stonefont {\n    \tfont-family: stonefont;\n\t}\n\t.movie-stats-container .movie-index .box .stonefont {\n    \tfont-size: 30px;\n\t}\n\t.movie-stats-container .movie-index .movie-index-content .index-right {\n\t    margin-left: 54px;\n\t    font-size: 12px;\n\t}\n\t.movie-stats-container .movie-index .movie-index-content .star-wrapper {\n\t    width: 130px;\n\t    height: 15px;\n\t    position: relative;\n\t    /*background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAAXNSR…6S4us6l62wa1DjEHrgZ5YkNs34vsMTQ76UYYU+5hG2ilE8ABzT5mRcPmFIAAAAAElFTkSuQmCC);*/\n\t    background-repeat: repeat-x;\n\t\tmargin-bottom: 4px;\n\t}\n\t.movie-stats-container .movie-index .movie-index-content .star-wrapper .star-on {\n\t    height: 15px;\n\t    background-image: url(\"../images/lightStar.jpg\");\n\t    background-repeat: repeat-x;\n\t}\n\t.main-inner{\n\t\t/*background: white;*/\n\t}\n\t.tags-panel {\n\t    border: 1px solid #e5e5e5;\n\t    padding: 0 20px;\n\t    margin: 40px 0;\n\t    position: relative;\n\t}\n\t.tags-panel li, .tags-panel ul {\n\t    margin: 0;\n\t    padding: 0;\n\t    list-style-type: none;\n\t}\n\t.tags-title {\n\t    height: 24px;\n\t    line-height: 24px;\n\t    float: left;\n\t    color: #999;\n\t    font-size: 14px;\n\t}\n\t.tags-panel ul.tags {\n    \tmargin-left: 40px;\n\t}\n\t.tags li.active {\n\t    background: #f34d41;\n\t    color: #fff;\n\t}\n\t.tags li {\n\t    border-radius: 14px;\n\t    padding: 3px 9px;\n\t    display: inline-block;\n\t    margin-left: 12px;\n\t}\n\t.tags li.active a {\n    \tcolor: #fff;\n\t}\n\t.tags li a {\n\t    color: #333;\n\t    font-size: 14px;\n\t}\n\t.tags-line-border {\n    \tborder-top: 1px dashed #e5e5e5;\n\t}\n\t.tags-line {\n    \tpadding: 10px 0!important;\n\t}\n\t.cinemas-list .cinemas-list-header {\n\t    font-size: 18px;\n\t    color: #333;\n\t    border-left: 4px solid #f03d37;\n\t    padding-left: 6px;\n\t    line-height: 18px;\n\t    margin: 0;\n\t}\n\t.cinemas-list .cinema-cell {\n\t    display: block;\n\t    padding: 20px 0;\n\t    border-bottom: 1px dashed #e5e5e5;\n\t}\n\t.cinemas-list .cinema-info {\n\t    display: inline-block;\n\t    max-width: 80%;\n\t}\n\t.cinemas-list .cinema-name {\n\t    display: inline-block;\n\t    font-size: 16px;\n\t    line-height: 18px;\n\t\tcolor: #333;\n\t\ttext-decoration: none;\n\t    margin-bottom: 10px;\n\t}\n\t.cinemas-list .cinema-address {\n\t    font-size: 14px;\n\t    line-height: 14px;\n\t    color: #999;\n\t}\n\t.cinemas-list .buy-btn {\n\t    float: right;\n\t    width: 80px;\n\t    height: 45px;\n\t    line-height: 45px;\n\t    margin-left: 36px;\n\t}\n\t.cinemas-list .buy-btn a {\n\t    display: inline-block;\n\t    width: 100%;\n\t    height: 30px;\n\t    color: #fff;\n\t    background-color: #f03d37;\n\t    font-size: 14px;\n\t    line-height: 30px;\n\t    border-radius: 100px;\n\t    text-align: center;\n\t    -webkit-box-shadow: 0 2px 10px -2px #f03d37;\n\t\tbox-shadow: 0 2px 10px -2px #f03d37;\n\t\ttext-decoration: none;\n\t}\n\t.cinemas-list .price {\n\t    float: right;\n\t    font-size: 12px;\n\t    color: #999;\n\t    height: 45px;\n\t    line-height: 45px;\n\t}\n\t.cinemas-list .price .rmb {\n    \tmargin-right: -4px;\n\t}\n\t.cinemas-list .price .price-num {\n\t    font-size: 16px;\n\t    margin-right: -3px;\n\t    font-weight: 700;\n\t}\n\t.red {\n   \t\tcolor: #f03d37;\n\t}\n\t.cinema-pager {\n    \ttext-align: center;\n\t}\n\t.list-pager {\n\t\tdisplay: block;\n\t    list-style-type: disc;\n\t    margin-block-start: 1em;\n\t    margin-block-end: 1em;\n\t    margin-inline-start: 0px;\n\t    margin-inline-end: 0px;\n\t    padding-inline-start: 40px;\n\t}\n\t.list-pager li.active {\n\t    border-color: #ef4238;\n\t    background-color: #ef4238;\n\t}\n\t.list-pager li {\n\t    display: inline-block;\n\t    height: 30px;\n\t    margin: 0 4px;\n\t    border: 1px solid #d8d8d8;\n\t    line-height: 30px;\n\t    text-align: center;\n\t    color: #999;\n\t}\n\t.list-pager li.active a {\n    \tcolor: #fff;\n\t}\n\t.list-pager a {\n\t    display: block;\n\t    padding: 0 12px;\n\t    color: #333;\n\t}\n\n\t.list-pager a {\n\t    font-size: 14px;\n\t}\n\t.banner2 .action-buyBtn a{\n\t\ttext-decoration: none;\n\t}\n\t.moviedetail{\n\t\theight: 40px !important;\n\t\twidth: 20px !important;\n\t\tbackground-color: rgba(red, green, blue, 0.5);\n\t}\n"
  },
  {
    "path": "src/main/webapp/static/css/center.css",
    "content": ".container{\n\tpadding: 0;\n\twidth: 1200px;\n\theight: 1200px;\n\tmargin-bottom: 100px;\n}\n.container .contents .nav-next{\n\tfloat: left;\n\twidth: 200px;\n\theight: 1198px;\n\tbackground-color: #f4f3f4;\n\tborder: 1px solid #ddd;\n}\n.container .contents .nav-next .nav-title{\n\tmargin: 40px auto 30px;\n\ttext-align: center;\n}\n.container .contents .nav-next a{\n\tfont-size: 18px;\n\ttext-align: center;\n\tdisplay: block;\n\ttext-decoration: none;\n\tcursor: pointer;\n\theight: 40px;\n\twidth: 100%;\n\tline-height: 40px;\n}\n.container .contents .nav-next .active{\n\tcolor: #fff;\n\tbackground-color: #ed3931;\n}\n\n.container .contents .nav-body{\n\tfloat: left;\n\toverflow: auto;\n\twidth: 940px;\n\theight: 1198px;\n\tborder: 1px solid #ddd;\n\tpadding-left: 40px;\n}\n.container .contents .nav-body .one, .two, .three{\n\tfloat: left;\n\twidth: 100%;\n\theight: 100%;\n}\n.container .contents .nav-body .one .title{\n\tfont-size: 18px;\n\tcolor: #ec443f;\n\tpadding: 26px 0;\n}\n.container .contents .nav-body .one hr{\n\tmargin-bottom: 30px;\n}\n.container .contents .nav-body .one .order-box{\n\theight: 186px;\n\twidth: (100%-40);\n\tmargin: 0 40px 30px 0;\n\tborder: 1px solid #ddd;\n}\n.container .contents .nav-body .one .order-box .order-head{\n\tbackground-color: #f7f7f7;\n\tpadding: 16px 20px;\n}\n.container .contents .nav-body .one .order-box .order-head .order-date{\n\tfont-size: 15px;\n\tmargin-right: 30px;\n}\n.container .contents .nav-body .one .order-box .order-head .order-id{\n\tfont-size: 14px;\n\tcolor: #999;\n}\n.container .contents .nav-body .one .order-box .order-head .order-delete{\n\tfont-size: 15px;\n\tfloat: right;\n}\n.container .contents .nav-body .one .order-box .order-body{\n\tpadding: 20px 0 20px 20px;\n\tfloat: left;\n\theight: 133px;\n\twidth: 100%;\n}\n.container .contents .nav-body .one .order-box .order-body .poster{\n\tborder: 2px solid #fff;\n\tbox-shadow: 1px 2px 0 #eee;\n\twidth: 70px;\n\theight: 95px;\n\tmargin-right: 11px;\n\tfloat: left;\n}\n.container .contents .nav-body .one .order-box .order-body .poster img{\n\twidth: 100%;\n\theight: 100%;\n}\n.container .contents .nav-body .one .order-box .order-body .order-content{\n\twidth: 49%;\n\theight: 100%;\n\tfloat: left;\n}\n.container .contents .nav-body .one .order-box .order-body .order-content .movie-name{\n\tfont-size: 16px;\n    font-weight: 700;\n    color: #333;\n    margin: 4px 0 7px -6px;\n}\n.container .contents .nav-body .one .order-box .order-body .order-content .cinema-name{\n\tfont-size: 12px;\n    color: #999;\n    margin-bottom: 4px;\n}\n.container .contents .nav-body .one .order-box .order-body .order-content .hall-ticket{\n\tfont-size: 12px;\n    color: #999;\n    margin-bottom: 4px;\n}\n.container .contents .nav-body .one .order-box .order-body .order-content .show-time{\n\tfont-size: 12px;\n    color: #f03d37;\n}\n.container .contents .nav-body .one .order-box .order-body .order-price{\n\tfloat: left;\n\tfont-size: 14px;\n    color: #333;\n    width: 12%;\n    line-height: 95px;\n}\n.container .contents .nav-body .one .order-box .order-body .order-status{\n\tfloat: left;\n\tfont-size: 14px;\n    color: #333;\n    width: 12%;\n    line-height: 95px;\n}\n.container .contents .nav-body .one .order-box .order-body .actions{\n\tfloat: right;\n\tfont-size: 14px;\n    color: #333;\n    width: 12%;\n\tline-height: 95px;\n\ttext-decoration: none;\n}\n.container .contents .nav-body .one .order-box .order-body .actions a{\n\ttext-decoration: none;\n}\n\n\n\n\n\n.container .contents .nav-body .two .title{\n\tfont-size: 18px;\n\tcolor: #ec443f;\n\tpadding: 26px 0;\n}\n.container .contents .nav-body .two hr{\n\tmargin-bottom: 30px;\n}\n.container .contents .nav-body .two .avatar-container{\n\twidth: 270px;\n\tfloat: left;\n\tmargin-left: 70px;\n\ttext-align: center;\n}\n.container .contents .nav-body .two .avatar-container img{\n\twidth: 258px;\n\theight: 258px;\n}\n.container .contents .nav-body .two .avatar-container .update-image{\n\tposition: relative;\n}\n.container .contents .nav-body .two .avatar-container .update-image .upload-btn{\n\tcursor: pointer;\n    margin: 20px auto 0;\n    width: 182px;\n    height: 56px;\n    line-height: 56px;\n    color: #5b5b5b;\n    background-color: #e6e6e6;\n    border-radius: 10px;\n    border: 1px;\n    font-size: 18px;\n    padding: 0;\n}\n.container .contents .nav-body .two .avatar-container .update-image #fileUpload{\n\tcursor: copy;\n\tposition: absolute;\n\twidth: 185px;\n\theight: 60px;\n    top: 18px;\n    right: 42px;\n    opacity: 0;\n    bottom: -50px;\n    direction: ltr;\n    font-size: 200px !important;\n}\n.container .contents .nav-body .two .avatar-container .tips{\n\tmargin-top: 10px;\n    color: #999;\n    font-size: 18px;\n    line-height: 30px;\n}\n.container .contents .nav-body .two .avatar-body{\n\tfloat: left;\n    width: 495px;\n\tmargin-left: 58px;\n\tmargin-top: 100px;\n}\n.container .contents .nav-body .two .avatar-body .userexinfo-form-section:first-child{\n\tmargin-top: 0;\n}\n.container .contents .nav-body .two .avatar-body .userexinfo-form-section{\n\tcolor: #666;\n    position: relative;\n    margin: 20px 0;\n    padding-left: 90px;\n    height: 30px;\n    line-height: 30px;\n    font-size: 14px;\n}\n.container .contents .nav-body .two .avatar-body .userexinfo-form-section p{\n\tposition: absolute;\n    top: 0;\n    left: 0;\n    width: 80px;\n    text-align: right;\n    color: #333;\n    padding: 0;\n\tmargin: 0;\n\tfont-size: 16px;\n}\n.container .contents .nav-body .two .avatar-body .userexinfo-btn-section{\n\tcolor: #666;\n    position: relative;\n    margin-top: 40px;\n    padding-left: 90px;\n    line-height: 30px;\n    font-size: 14px;\n}\n.container .contents .nav-body .two .avatar-body .userexinfo-btn-section .form-save-btn{\n\tcursor: pointer;\n    border-radius: 5px;\n    width: 100px;\n    height: 40px;\n    color: #fff;\n    font-size: 18px;\n    line-height: 40px;\n    border: none;\n    background-color: #ed3931;\n\tpadding: 0;\n\ttext-align: center;\n}\n\n\n\n\n.container .contents .nav-body .three .title{\n\tfont-size: 18px;\n\tcolor: #ec443f;\n\tpadding: 26px 0;\n}\n.container .contents .nav-body .three hr{\n\tmargin-bottom: 30px;\n}\n.container .contents .nav-body .three .avatar-body{\n\tmargin-left: 30%;\n}\n.container .contents .nav-body .three .avatar-body .userexinfo-form-section{\n\tcolor: #666;\n    position: relative;\n    margin: 20px 0;\n    padding-left: 90px;\n    height: 30px;\n    line-height: 30px;\n    font-size: 14px;\n}\n.container .contents .nav-body .three .avatar-body .userexinfo-form-section p{\n\tposition: absolute;\n    top: 0;\n    left: 0;\n    width: 80px;\n    text-align: right;\n    color: #333;\n    padding: 0;\n\tmargin: 0;\n\tfont-size: 16px;\n}\n.container .contents .nav-body .three .avatar-body .userexinfo-btn-section{\n\tcolor: #666;\n    position: relative;\n    margin-top: 40px;\n    line-height: 30px;\n\tfont-size: 14px;\n\tmargin-left: 15% !important;\n}\n.container .contents .nav-body .three .avatar-body .userexinfo-btn-section .password-save-btn{\n\tcursor: pointer;\n    border-radius: 5px;\n    width: 100px;\n    height: 40px;\n    color: #fff;\n    font-size: 18px;\n    line-height: 40px;\n    border: none;\n    background-color: #ed3931;\n\tpadding: 0;\n\ttext-align: center;\n}\n\n\n.two .file {\n\tmargin-top: 20px; \n    position: relative;\n    display: inline-block;\n    background: #009688;\n    /* border: 1px solid rgb(44, 243, 77); */\n    border-radius: 4px;\n    padding: 4px 12px;\n    overflow: hidden;\n    color: #fff;\n    text-decoration: none;\n    text-indent: 0;\n\tline-height: 20px;\n\tcursor: pointer;\n}\n.two .file input {\n    position: absolute;\n    font-size: 100px;\n    right: 0;\n    top: 0;\n\topacity: 0;\n\tcursor: pointer;\n}\n.two .file:hover {\n    background: #00ad9c;\n    /* border-color: #009688; */\n    color: #fff;\n\ttext-decoration: none;\n\tcursor: pointer;\n}"
  },
  {
    "path": "src/main/webapp/static/css/footer.css",
    "content": ".footer{\n    margin-top: 50px;\n    height: 211px;\n    background-color: #262426;\n }\n .footer p{\n\tcolor: #666;\n }\n .footer p a{\n\t color:#ef4238;\n }\n .footer span {\n    display: inline-block;\n    border-left: 1px solid #444;\n    margin: 0 7px;\n    height: 12px;\n    position: relative;\n    top: 1px;\n}\n.footer div {\n    text-align:center;\n    padding: 57px 0;\n}"
  },
  {
    "path": "src/main/webapp/static/css/header.css",
    "content": ".header{\n/*\theight: 80px;\n\tbackground: white;\n\tborder-bottom: 1px solid #d8d8d8;*/\n\t/*height: 80px;\n\tposition: fixed;\n\ttop: 0;*/\n\tz-index: 999;\n\twidth: 100%;\n\tmin-width: 1200px;\n\tbackground-color: #fff;\n}\n.header-top{\n\theight: 81px;\n\tborder-bottom: 1px solid #d8d8d8;\n}\n.header .header-inner{\n\twidth: 1420px;\n\theight: 80px;\n\tmargin: 0 auto;\n}\n.header .header-inner h1{\n\tfloat: left;\n\twidth: 260px;\n\theight: 80px;\n}\n.header .header-inner .logo{\n\tbackground-image: url(\"../images/logo_h.jpg\");\n\tdisplay: block;\n\tfloat: left;\n\twidth: 150px;\n    height: 80px;\n    margin-left: 130px;\n    background-position-y: center;\n    background-repeat: no-repeat;\n    background-size: auto 65px;\n}\n.header .nav{\n\twidth: 400px;\n\theight: 80px;\n\tdisplay: block;\n\toverflow: hidden;\n\tmargin-left: 40px;\n\tfloat: left;\n}\n.header .nav ul{\n\n}\n.header .nav ul li{\n\twidth: 80px;\n\theight: 80px;\n\tfloat: left;\n}\n.header .nav ul li a{\n\ttext-decoration: none;\n\ttext-align: center;\n\tdisplay: inline-block;\n\theight: 80px;\n\tline-height: 80px;\n\twidth: 80px;\n\tfont-size: 18px;\n\tcolor: #333;\n}\n.header .nav ul li a:hover{\n\tcolor: #fff;\n\tbackground-color: #ef4238;\n}\n.header .app-download{\n\tfloat: left;\n\tbackground: url(\"../images/app.jpg\");\n\twidth: 162px;\n\theight: 80px;\n}  \n.header form{\n\twidth: 260px;\n\theight: 40px;\n\tfloat: right;\n\tmargin: 20px 10px 0 0;\n\tposition: relative;\n}\n\n.header form .search{\n\n\tdisplay: inline-block;\n\theight: 40px;\n\tline-height: 1.2;\n\twidth: 260px;\n\tpadding: 0 40px 0 20px;\n\tborder: 1px solid #ccc;\n\tfont-size: 14px;\n\tborder-radius: 30px;\n\tbackground-color: #faf8fa;\n\toverflow: hidden;\n\tcolor: #333;\n}\n.header form .submit{\n\tdisplay: inline-block;\n\tposition: absolute;\n\tleft: 220px;\n\ttop: 0;\n\theight: 40px;\n\twidth: 40px;\n\tbackground-color: #ef4238;\n\tborder-radius: 30px;\n\tbackground-image: url(\"../images/search.jpg\");\n\tcursor: pointer;\n}\n.header .user-info{\n\tfloat: right;\n\tposition: relative;\n\tz-index: 9999;\n\theight: 100%;\n\tmargin-right: 200px;\n}\n.header .user-info .user-avatar {\n\tdisplay: block;\n\tborder: 1px solid transparent;\n\tborder-top: none;\n\tborder-bottom: none;\n\tpadding: 0 10px;\n\twidth: 56px;\n\theight: 100%;\n}\n.header .user-info .user-avatar:hover{\n\n}\n.header .user-info .user-avatar img {\n\tmargin-top: -20px;\n\twidth: 42px;\n\theight: 42px;\n\tborder-radius: 50%;\n\tcursor: pointer;\n}\n.caret {\n\tdisplay: inline-block;\n\twidth: 0;\n\theight: 0;\n\tmargin-left: 2px;\n\tvertical-align: middle;\n\tborder-top: 5px solid #666;\n\tborder-right: 5px solid transparent;\n\tborder-left: 5px solid transparent;\n\t-webkit-transition: all .2s ease;\n\ttransition: all .2s ease;\n}\n.header .user-info .user-avatar .caret {\n\tposition: absolute;\n\ttop: 39px;\n\tright: 10px;\n}\n.header .user-info .user-menu {\n\tdisplay: none;\n\tposition: absolute;\n\tright: 0;\n\ttop: 80px;\n\tborder: 1px solid #d8d8d8;\n\tbackground-color: #fff;\n\tfont-size: 14px;\n\tcolor: #333;\n\ttext-align: right;\n\tpadding: 15px 26px 5px;\n\ttext-align: center;\n}\n.header .user-info .user-menu li {\n\tmargin-bottom: 6px;\n}\n.header .user-info .user-menu li>a {\n\tcolor: #999;\n\tdisplay: block;\n\tword-break: keep-all;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n.header form, .header h3, .header input, .header li, .header ul{\n\tborder:none;\n}\n.header .banner{\n\theight: 440px;\n\twidth: 100%;\n\tmin-width: 1200px;\n}\n.header .banner .slider{\n\tposition: relative;\n\tz-index: 1;\n\tdisplay: block;\n\theight: 440px;\n\toverflow: hidden;\n\twidth: 1420px;\n\tmargin: 0 auto;\n\tmargin-bottom: 88px!important;\n}\n\t  \n\n\n.fu-nav{\n\tbackground-color: #47464a !important;\n\theight: 60px;\n\ttext-align: center;\n}\n.fu-nav .layui-this a{\n\tcolor: #ef4238 !important;\n}\n.fu-nav li{\n\twidth: 144px;\n}\n.fu-nav .layui-this:after, .layui-nav-bar,  li:after{\n\tbackground-color: rgba(177, 25, 131, 0) !important;\n}\n.fu-nav a{\n\tfont-size: 16px;\n\ttext-decoration: none;\n\tcursor: pointer;\n}\n.layui-carousel img{\n\twidth: 100%;\n\theight: auto;\n}\n.nav-image a{\n\ttext-align: center;\n\theight: 35px;\n\ttext-decoration: none;\n\tline-height: 40px;\n}\n\n\n.header-li{\n\twidth: 42px;\n    height: 42px;\n    margin-top: 18px;\n}\nbody .layui-nav .layui-nav-more\n{\n\tdisplay: none;\n}"
  },
  {
    "path": "src/main/webapp/static/css/login.css",
    "content": "﻿*{\n  margin: 0px;\n  padding: 0px;\n}\nbody{\n  background-image: url('../images/2.jpg');\n}\n\n.screen{\n  float: left;\n  text-align: center;\n}\n.screen .title{\n  font-size: 72px;\n  color: #fff;\n}\n.screen .ineer_one{\n  margin-top: 20px;\n  font-size: 18px;\n  color: rgba(255, 255, 255, 0.7);\n  font-weight: inherit;\n  margin-right: 60px;\n}\n.screen .ineer_two{\n  font-size: 18px;\n  color: rgba(255, 255, 255, 0.7);\n  font-weight: inherit;\n  margin-left: 60px;\n}\n\n\n\n\n.content{\n  width: 420px;\n  height: 500px;\n  background-color: rgba(255, 255, 255, 0.3);\n  border-radius: 8px;\n  box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);\n}\n.content .tab{\n  width: 420px;\n  height: 50px;\n  border-radius: 8px 8px 0px 0px;\n}\n.content .tab li{\n  cursor: default;\n  text-align: center; \n  line-height: 50px;\n  font-size: 24px;\n  width: 49.9%;\n  height: 100%;\n  list-style: none;\n  float: left;\n  color: #fff;\n  font-family: '隶书';\n}\n.content .tab .login{\n  cursor: pointer;\n  border-radius: 8px 0px 0px 0px;\n  background-color: rgba(255, 255, 255, 0);\n}\n.content .tab .register{\n  cursor: pointer;\n  border-radius: 0px 8px 0px 0px;\n  background-color: rgba(255, 255, 255, 0.2);\n}\n\n\n\n.content .page .childpage{\n  margin-top: -10px; \n  background: rgba(255, 255, 255, 0);\n  width: 420px;\n  height: 420px;\n  border-radius: 0px 0px 8px 8px;\n  text-align: center;\n}\n\n\n.content .page .childpage .login_page div{\n  margin-top: 30px;\n}\n.content .page .childpage .lo_error{\n  margin-top: 20px;\n}\n.content .page .childpage .login_error{\n  color: rgb(209, 0, 0);\n}\n.content .page .childpage .login_version{\n  margin-top: 90px;\n  color: #ccc;\n}\n.content .page .childpage .login_btn{\n  width: 240px;\n}\n.content .page .childpage .login_page #UserName, #PassWord{\n  width: 240px;\n  height: 30px;\n  border: none;\n  background-color: rgba(255, 255, 255, 0.3);\n  border-radius: 5px;\n}\n.content .page .childpage .login_page label{\n  color: #fff;\n}\n\n\n.content .page .childpage .login_title, .register_title{\n  margin-top: 40px;\n  font-size: 32px;\n  color: #fff;\n}\n.content .page .childpage .register_page div{\n  margin-top: 10px;\n}\n.content .page .childpage .register_page #UserName, #PassWord, #Email{\n  width: 240px;\n  height: 30px;\n  border: none;\n  background-color: rgba(255, 255, 255, 0.3);\n  border-radius: 5px;\n}\n.content .page .childpage .register_page #Test{\n  width: 130px;\n  height: 30px;\n  border: none;\n  background-color: rgba(255, 255, 255, 0.3);\n  border-radius: 5px;\n}\n.content .page .childpage .register_page #TestNum{\n  cursor: pointer;\n  font-weight: bold;\n  text-align: center;\n  color: red;\n  margin-left: 20px;\n  width: 88px;\n  height: 30px;\n  border: none;\n  background-color: rgba(255, 255, 255, 0.8);\n  border-radius: 5px;\n}\n.content .page .childpage .register_page label{\n  color: #fff;\n}\n.content .page .childpage .register_error{\n  color: rgb(209, 0, 0);\n}\n.content .page .childpage .re_error{\n  margin-top: 10px;\n}\n.content .page .childpage .register_btn{\n  width: 240px;\n}\n.content .page .childpage .register_version{\n  margin-top: 10px;\n  color: #ccc;\n}\n\n.screen .big_logo{\n  background-image: url(\"../images/logo_t.jpg\");\n  background-color: rgba(255, 255, 255, 0.2);\n  border-radius: 8px;\n\twidth: 200px;\n  height: 200px;\n  background-repeat: no-repeat;\n  background-size: 200px auto;\n}"
  },
  {
    "path": "src/main/webapp/static/css/main.css",
    "content": ".main{\n\toverflow: hidden;\n\t/* height: 2159px; */\n\t/*background-color: green;*/\n}\n.main .main-inner{\n\twidth: 981px;\n\t/* height: 2079px; */\n\tmargin: 0 auto 0 auto;\n}\n.main .main-buyticket{\n\twidth: 1200px;\n\t/* height: 2079px; */\n\tmargin: 0 auto 0 auto;\n}\n.main .movie-grid{\n\tmargin-top: 10px;\n\tfloat: left;\n\t/*width: 738px;*/\n\twidth: 850px;\n\t/* height: 1414px; */\n\tmargin-right: 40px;\n}\n.main .main-page{\n\twidth: 1271px !important;\n\theight: 1760px !important;\n}\n.panel-header {\n\toverflow: hidden;\n\theight: 26px;\n\tline-height: 26px;\n}\n.panel-title {\n\tfont-size: 26px;\n\tcolor: #ffb400;\n}\n.panel-arrow {\n\tbackground: url(\"../images/arrow.jpg\") top no-repeat;\n}\n.panel-arrow {\n\tdisplay: inline-block;\n\twidth: 8px;\n\theight: 14px;\n\tvertical-align: top;\n}\n.panel-more {\n\tfont-size: 14px;\n\tline-height: 16px;\n\tfloat: right;\n\tmargin-top: 10px;\n}\n.panel-content{\n\theight: 550px;\n\t\n}\n.textcolor_red {\n\tcolor: #ef4238!important;\n}\n.textcolor_blue{\n\tcolor: #2d98f3!important;\n}\n.main .aside{\n\tfloat: right;\n\twidth: 360px;\n\t/* height: 2079px; */\n\t\n}\n.movie-list{\n\tmargin-top: 23px;\n}\n.movie-list li{\n\tmargin: 0 45px 28px 0px;\n\tfloat: left;\n\twidth: 160px;\n\theight: 259px;\n\tbackground: #fff;\n\tborder: 1px solid #efefef;\n}\n.movie-poster{\n\theight: 220px;\n}\n.movie-poster img {\n\tborder-style: none;\n\theight: 220px;\n\twidth: 160px;\n}\n.movie-poster .movie-overlay {\n\tcolor: #fff;\n\tposition: relative;\n\ttop: -26px;\n\tleft: 0;\n\t/*background: green;*/\n}\n.movie-title-padding {\n\tmargin-right: 35px;\n}\n.movie-title {\n\tfont-size: 16px;\n\tline-height: 22px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tmargin: 0 10px;\n}\n.movie-score {\n\tcolor: #ffb400;\n\tfloat: right;\n\tmargin-right: 10px;\n}\n.movie-detail-strong {\n\theight: 39px;\n\tline-height: 39px;\n}\n.movie-detail {\n\tcursor: pointer;\n\tposition: relative;\n\ttop: -19px;\n\twidth: 100%;\n\theight: 41px;\n\tline-height: 41px;\n\ttext-align: center;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n.movie-detail a:hover{\n\ttext-decoration: none;\n\tbackground: #ef4238;\n\tcolor: #fff;\n}\n.movie-sale .active {\n\tcolor: #ef4238;\n}\n.movie-sale a {\n\tdisplay: block;\n\twidth: 160px;\n\theight: 40px;\n\tcolor: #999;\n\tfont-size: 14px;\n}\n.movie-item {\n\twidth: 160px;\n\theight: 260px;\n}\n.movie-ver {\n\twidth: 69px;\n\theight: 25px;\n\tposition: relative;\n\ttop: -280px;\n\tleft: -2px;\n\tfont-size: 12px;\n\tcolor: #fff;\n}\n.movie-ver i.imax3d {\n\tdisplay: block;\n\twidth: 69px;\n\theight: 25px;\n\tbackground-image: url(\"../images/3Dmax.jpg\");\n}\n.main .panel{\n\tmargin-top: 28px;\n}\n.sidepanel{\n\tmargin-top: 10px !important;\n}\n.movie-wish {\n\twidth: 158px;\n\theight: 41px;\n\tfont-size: 14px;\n\tcolor: #ffb400;\n\tbackground-color: #fbfbfb;\n\ttext-align: left;\n\tpadding-left: 10px;\n}\n.movie-presale-sep {\n\tborder-right: 1px dotted #e5e5e5;\n}\n.movie-presale a {\n\tcursor: pointer;\n\twidth: 50%;\n\tbox-sizing: border-box;\n\tdisplay: inline-block;\n\tvertical-align: top;\n\tcolor: #999;\n\tfont-size: 14px;\n\tbackground: #fff;\n}\n.movie-presale a:hover{\n\tbackground: #2d98f3;\n}\n.movie-presale{\n\tborder: 1px solid #eee;\n}\n\n.tags-line a{\n\ttext-decoration: none;\n}\n.tags-line a:hover{\n\tcolor: #f34d41;\n}\n.list-pager a{\n\ttext-decoration: none;\n}\n.list-pager li:hover{\n\tborder: 1px solid #f34d41;\n}\n.list-pager .active{\n\tbackground: #f34d41;\n    color: #fff;\n}\n.main-detail{\n\twidth: 1131px !important;\n}\n.main-movielist{\n\twidth: 1100px !important;\n\tmargin: 0 0 0 400px !important;\n}\t\n.main .main-bodyz{\n\twidth: 1100px !important;\n}\n.movieList{\n\twidth: 1100px !important;\n}\n .main .ranking-imgs{\n \theight: 78px;\n \twidth: 120px;\n }"
  },
  {
    "path": "src/main/webapp/static/css/main2.css",
    "content": "\n*{\n    margin: 0;\n    padding: 0;\n}\n.aside {\n    float: right;\n    width: 360px;\n}\n.ranking-box-wrapper .panel-content {\n    height: 450px;\n    width: 100%;\n    margin-top: 23px;\n}\n.panel-content {\n    width: 100%;\n    margin-top: 23px;\n}\n.main .panel {\n    margin-top: 28px;\n}\n.panel-header {\noverflow: hidden;\nheight: 26px;\nline-height: 26px;\n}\n.panel-title .textcolor_red{\n    font-size: 26px;\n}\n.panel-title .textcolor_blue{\n    font-size: 26px;\n}\n.ranking-index-1{\n    margin-bottom:11px;\n    border: 1px solid #efefef;\n}\n.ranking-box .ranking-top-left{\n    width: 120px;\n    height: 78px;\n    float: left;\n    position: relative;\n}\n.ranking-top-right{\n        padding-left:10px;\n        overflow: hidden;\n        height:78px;\n        line-height: 78px;\n}\n.ranking-box .ranking-top-right-main{\n    width: 220px;\n}\n.ranking-top-right-main{\n    display: inline-block;\n    line-height:1;\n    vertical-align: middle;\n}\n    .ranking-top-right .ranking-top-moive-name{\n    margin: 0;\n    padding: 0;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    font-size: 18px;\n    color: #333;\n    line-height: 1.4;\n}\n\n    .ranking-top-right .ranking-top-wish,.textcolor_red {\n    color: #ef4238;\n}\n.ranking-top-right .ranking-top-wish{\nmargin-top:12px;\nfont-size: 14px;\n}\n.stonefont{\n    font-size: 14px;\n}\n.ranking-item .normal-link{\n    display: block;\n    height: 35px;\n    line-height: 35px;\n}\n.ranking-index-2 .ranking-index,\n.ranking-index-3 .ranking-index{\n    color:#ef4238;\n}\n.ranking-item .ranking-index{\n    display: inline-block;\n    width:20px;\n}\n.ranking-index{\n    color:#999;\n    font-size:18px;\n    vertical-align:top;\n}\n.ranking-item .ranking-movie-name{\n    display: inline-block;\n    max-width: 190px;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    font-size: 16px;\n    color: #333;\n    vertical-align: top;\n}\n.ranking-num-info{\n    float: right;\n    font-size: 14px;\n}\n.ranking-num-info {\n    color:#ef4238;\n}\n\n/* 222 */\n.textcolor_orange {\n    color: #ffb400!important;\n}\n.panel-more {\n    font-size: 14px;\n    line-height: 16px;\n    float: right;\n    margin-top: 10px;\n}\n.panel-content {\n    width: 100%;\n    margin-top: 23px;\n}\n.ranking-mostExpect .ranking-top-left {\n    width: 140px;\n    height: 194px;\n    float: left;\n    position: relative;\n}\n.ranking-mostExpect .ranking-top-right {\n    height: 194px;\n    line-height: 194px;\n}\n.ranking-top-right{\n    padding-left: 10px;\n    overflow: hidden;\n}\n.ranking-top-right .ranking-release-time {\n    margin-top: 12px;\n    color: #999;\n}\n.ranking-top-right .ranking-top-wish {\n    margin-top: 12px;\n    font-size: 14px;\n    color: #ffb400;\n}\n.ranking-mostExpect .ranking-index-2, .ranking-mostExpect .ranking-index-3 {\n    border: 1px solid #efefef;\n    position: relative;\n    width: 170px;\n    float: left;\n    margin-top: 20px;\n    margin-bottom: 20px;\n    padding-bottom: 8px;\n}\n.ranking-mostExpect .ranking-index-2 .ranking-index, .ranking-mostExpect .ranking-index-3 .ranking-index {\n    position: absolute;\n    padding-left: 4px;\n    width: 16px;\n    line-height: 20px;\n    color: #fff;\n    background-color: #ffb400;\n}\n.ranking-mostExpect .ranking-index-2 .name-link, .ranking-mostExpect .ranking-index-3 .name-link {\n    display: block;\n    font-size: 18px;\n    color: #333;\n    margin-top: 8px;\n    margin-left: 10px;\n    margin-right: 10px;\n}\n.ranking-mostExpect .ranking-index-2 .ranking-num-info, .ranking-mostExpect .ranking-index-3 .ranking-num-info {\n    float: none;\n    display: inline-block;\n    font-size: 14px;\n    margin-top: 6px;\n    margin-left: 10px;\n}\n.ranking-num-info{\n    color:#fdb863;  \n}\n.ranking-item .normal-link {\n    display: block;\n    height: 35px;\n    line-height: 35px;\n    margin-top: 5px; \n}\n.ranking-num-info {\n    float: right;\n    color: #fdb863;\n    font-size: 14px;\n}\n.ranking-mostExpect .ranking-index-4 {\n    clear: both;\n}\n    .ranking-top100 .ranking-top-right {\n    height: 78px;\n    line-height: 78px;\n    padding-left: 10px;\n    overflow: hidden;\n}\n.ranking-top100 .ranking-top-left {\n    width: 120px;\n    height: 78px;\n    float: left;\n    position: relative;\n}\n.top100-wrapper {\n    margin-top: 100px;\n}\n.aside .most-expect-wrapper {\n    margin-top: 10px;\n}\n.ranking-index-2 ,.ranking-index-3{\n    color: #ef4238;\n}"
  },
  {
    "path": "src/main/webapp/static/css/manage.css",
    "content": ".container{\n\t/*padding: 0;*/\n\twidth: 1530px !important;\n\t/*height: 1200px;*/\n\t/*margin-bottom: 100px;*/\n}\n.container .contents .nav-next{\n\tfloat: left;\n\twidth: 200px;\n\theight: 1200px;\n\tbackground-color: #f4f3f4;\n\tborder: 1px solid #ddd;\n}\n.container .contents .nav-next .nav-title{\n\tmargin: 40px auto 30px;\n\ttext-align: center;\n}\n.container .contents .nav-next a{\n\tfont-size: 18px;\n\ttext-align: center;\n\tdisplay: block;\n\ttext-decoration: none;\n\tcursor: pointer;\n\theight: 40px;\n\twidth: 100%;\n\tline-height: 40px;\n}\n.container .contents .nav-next .active{\n\tcolor: #fff;\n\tbackground-color: #ed3931;\n}\n\n.container .contents .nav-body{\n\tfloat: left;\n\twidth: 1300px;\n\theight: 1200px;\n\tborder: 1px solid #ddd;\n\tpadding-left: 40px;\n}\n.container .contents .nav-body .one, .two, .three, .four, .five, .six{\n\tfloat: left;\n\twidth: 100%;\n\theight: 100%;\n}\n.container .contents .nav-body .title{\n\tfont-size: 18px;\n\tcolor: #ec443f;\n\tpadding: 26px 0;\n}\n.container .contents .nav-body hr{\n\tmargin-bottom: 30px;\n}\n\n\n\n\n\n/************************ 用户管理 ******************************/\n.container .one .userlist{\n\tmargin-right: 40px;\n}\n.addusertitle{\n\ttext-align: center;\n\tfont-size: 18px;\n\tmargin: 20px auto 20px;\n}\n.addusertext{\n\twidth: 60%;\n}\n.adduserbtn{\n\twidth: 100px;\n\tfloat: left;\n}\n.usercheck{\n\tmargin-left: 30px;\n\twidth: 400px;\n\tfloat: left;\n}\n.usercheck input{\n\twidth: 200px;\n\theight: 30px;\n\tfloat: left;\n}\n.usercheck button{\n\tfloat: left;\n}\n.layui-table-box{\n\tclear: both;\n}\n\n\n\n/************************ 电影管理 ******************************/\n.container .two .main-inner{\n\theight: 1090px;\n\toverflow-y: auto;\n}\n.container .two .main-inner .addMovie{\n\tmargin-bottom:30px;\n\theight:215px;\n}\n.container .two .main-inner .addMovie img{\n\tdisplay:block;\n\twidth:160;\n\theight:160;\n\tfloat:left;\n\tcursor:pointer;\n}\n.container .two .main-inner .addMovie span{\n\tfont-size: large;\n\tfloat: left;\n\tdisplay: block;\n\tclear: both;\n\tmargin-left: 42px;\n}\n.container .two .movies-list{\n\tmargin-top: 23px;\n}\n.container .two .movies-list li{\n\tmargin: 0 80px 60px 0px;\n\tfloat: left;\n\twidth: 160px;\n\theight: 259px;\n\tbackground: #fff;\n\tborder: 1px solid #efefef;\n}\n.container .two .movies-detail-strong {\n\theight: 39px;\n\tline-height: 39px;\n}\n.container .two .movies-detail {\n\tmargin-top: -1px;\n\tborder: 1px solid #eee;\n\tcursor: pointer;\n\tposition: relative;\n\ttop: -21px;\n\twidth: 100%;\n\theight: 41px;\n\tline-height: 41px;\n\ttext-align: center;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tbackground-color: #fff;\n}\n.container .two .movies-detail a:hover{\n\ttext-decoration: none;\n\tbackground: #ef4238;\n\tcolor: #fff;\n}\n.textside{\n\tfloat: left;\n\twidth: 450px;\n}\n.pictureside{\n\tfloat: left;\n\twidth: 300px;\n\ttext-align: center;\n}\n.pictureside .layui-upload{\n\tmargin: 50px 0px;\n\twidth: 300px;\n}\n.pictureside #file{\n\twidth: 80px;\n    height: 30px;\n}\n.pictureside .file {\n\tmargin-top: 20px; \n    position: relative;\n    display: inline-block;\n    background: #009688;\n    /* border: 1px solid rgb(44, 243, 77); */\n    border-radius: 4px;\n    padding: 4px 12px;\n    overflow: hidden;\n    color: #fff;\n    text-decoration: none;\n    text-indent: 0;\n\tline-height: 20px;\n\tcursor: pointer;\n}\n.pictureside .file input {\n    position: absolute;\n    font-size: 100px;\n    right: 0;\n    top: 0;\n\topacity: 0;\n\tcursor: pointer;\n}\n.pictureside .file:hover {\n    background: #00ad9c;\n    /* border-color: #009688; */\n    color: #fff;\n\ttext-decoration: none;\n\tcursor: pointer;\n}\n.pictureside .movie-picture{\n\tmargin-bottom: 20px;\n}\n.layui-upload-list{\n\tmargin: 0px !important;\n}\n.textside .layui-form-item{\n\tmargin-bottom: 2px !important;\n}\n.textside .layui-form-label {\n\twidth: 100px !important;\n}\n.textside .layui-btn {\n\tbackground-color: #fff;\n\tborder: 1px solid #ccc;\n\tcolor: #ccc;\n\tmargin-left: 10px;\n\twidth: 20px;\n}\n.textside .actor {\n\twidth: 110px;\n}\n\n\n\n\n\n\n.layui-upload-img{\n\tmax-width: 160px;\n\tmax-height: 220px;\n}\n\n/************************ 场次管理 ******************************/\n.container .one .schedulelist{\n\tmargin-right: 40px;\n}\n.addtitle{\n\ttext-align: center;\n\tfont-size: 18px;\n\tmargin: 20px auto 20px;\n}\n.addmoney{\n\twidth: 45%;\n}\n.addbtn{\n\twidth: 100px;\n\tfloat: left;\n}\n.schedulecheck{\n\tmargin-left: 30px;\n\twidth: 300px;\n\tfloat: left;\n}\n.schedulecheck input{\n\twidth: 200px;\n\theight: 30px;\n\tfloat: left;\n}\n.layui-table-box{\n\tclear: both;\n}\n.scheduleLabel {\n    float: left;\n    display: block;\n    padding: 9px 15px 9px 20px;\n    width: 100px;\n    font-weight: 400;\n    line-height: 20px;\n    text-align: right\n}\n.addselect {\n\twidth: 200px !important;\n}\n.schedule-div{\n\tmargin-left: 25px;\n}\n#scheduleadd {\n\twidth: 400px;\n}\n.layui-laydate{\n\tposition: fixed !important;\n}\n.drop-cinema dl{\n\tmax-height: 180px !important;\n}\n.drop-hall dl{\n\tmax-height: 120px !important;\n}\n.scheduleonall{\n\tfloat: left;\n}\n.scheduledownall{\n\tfloat: left;\n\tmargin-left: 30px;\n}\n.three .schedulelist{\n\tmargin-right: 40px;\n}\n\n\n\n\n\n\n\n\n/************************ 评论管理 ******************************/\n.container .four .commentlist{\n\tmargin-right: 40px;\n}\n.commentcheck{\n\tmargin-left: 30px;\n\twidth: 400px;\n\tfloat: left;\n}\n.commentcheck input{\n\twidth: 200px;\n\theight: 30px;\n\tfloat: left;\n}\n.commentcheck button{\n\tfloat: left;\n}\n\n\n/************************ 订单管理 ******************************/\n.container .five .ticketlist{\n\tmargin-right: 40px;\n}\n.ticketcheck{\n\tmargin-left: 30px;\n\twidth: 400px;\n\tfloat: left;\n}\n.ticketcheck input{\n\twidth: 200px;\n\theight: 30px;\n\tfloat: left;\n}\n.ticketcheck button{\n\tfloat: left;\n}\n.changeticketBtn{\n\tborder: 1px solid #ddd !important;\n\tposition: relative;\n\tleft: 1.5px;\n\tbackground-color: #fbfbfb !important;\n}\n.orderall{\n\tfloat: left;\n}\n.backorder{\n\tfloat: left;\n\tmargin-left: 30px\n}\n\n\n\n/************************ 退票审核 ******************************/\n.container .six .backticketlist{\n\tmargin-right: 40px;\n}\n.backticketcheck{\n\tmargin-left: 30px;\n\twidth: 400px;\n\tfloat: left;\n}\n.backticketcheck input{\n\twidth: 200px;\n\theight: 30px;\n\tfloat: left;\n}\n.backticketcheck button{\n\tfloat: left;\n}\n.changebackticketBtn{\n\tborder: 1px solid #ddd !important;\n\tposition: relative;\n\tleft: 1.5px;\n\tbackground-color: #fbfbfb !important;\n}\n\n\n"
  },
  {
    "path": "src/main/webapp/static/css/modify.css",
    "content": "﻿.Modifyform {\n              height: 18.75em;\n              width: 46em;\n              margin-top: 150px;\n              background: #fff;\n              position: absolute;\n             \n              left: 50%;\n              transform: translate(-50%,-50%);\n              text-transform: lowercase;\n              font-family: \"Bebas Neue\", Arial;\n              color: #fff;\n            }\n            \n            .Modifyform > div {\n              \n              height: 6.25em;\n              width: 100%;\n            }\n            \n            .username {\n              background-color: #4daf7c;\n            }\n            \n            .username::after {\n              content: \"\";\n              width: 0px;\n              height: 0px;\n              position: absolute;\n              border-style: solid;\n              border-width: 0.5em 0.469em 0 0.469em;\n              border-color: #4daf7c transparent transparent transparent;\n              top: 6.25em;\n              left: 50%;\n              margin-left: -0.496em;\n            }\n            \n            .password {\n              background-color: #404241;\n            }\n            \n            .password::after {\n              content: \"\";\n              width: 0px;\n              height: 0px;\n              position: absolute;\n              border-style: solid;\n              border-width: 0.5em 0.469em 0 0.469em;\n              border-color: #404241 transparent transparent transparent;\n              top: 12.5em;\n              left: 50%;\n              margin-left: -0.496em;\n            }\n            .type{\n                background-color: purple;\n            }\n            .type::after{\n              content: \"\";\n              width: 0px;\n              height: 0px;\n              position: absolute;\n              border-style: solid;\n              border-width: 0.5em 0.469em 0 0.469em;\n              border-color: purple transparent transparent transparent;\n              top: 18.7em;\n              left: 50%;\n              margin-left: -0.496em;\n            \n            }\n            .login {\n              background-color: #e9c85d;\n              display: table;\n            }\n            \n            .login span {\n              display: table-cell;\n              vertical-align: middle;\n              text-align: center;\n              font-size:3em;\n              cursor: pointer;\n            }\n            \n            .ModifyInput {\n              height: 1.8em;\n              width: 19.125em;\n              font-size: 2em;\n              text-align:center;\n              border: 0;\n              outline: 0;\n              color: #fff;\n              background: transparent;\n              border:0.033em #fff solid;\n              margin-left: 2.1875em;\n              margin-top: 0.8em;\n              font-family: \"Bebas Neue\", Arial;\n            }\n            \n            ::placeholder {\n              color: #fff;\n            }\n            \n            ::-moz-placeholder {\n              color: #fff;\n            }\n            \n            :-ms-input-placeholder {\n              color: #fff;\n            }\n            \n            ::-webkit-input-placeholder {\n              color: #fff;\n            }\n            .detailBox{\n                height: 8.25em;\n                background-color: #ccc;\n            }\n            #detail{\n               height: 4.5em;\n              width: 19.125em;\n              font-size: 2em;\n              text-align:center;\n              border: 0;\n              outline: 0;\n              color: #fff;\n              background: transparent;\n              border:0.033em #fff solid;\n              margin-left: 2.1875em;\n              margin-top: 1em;\n              font-family: \"Bebas Neue\", Arial;\n            }"
  },
  {
    "path": "src/main/webapp/static/css/movieDetail.css",
    "content": "\t.main-content {\n\t    width: 1130px;\n\t    float: left;\n\t}\n\t.tab-container .tab-title-container {\n\t\twidth: 1130px;\n\t\theight: 30px;\n    \tborder-bottom: 2px solid #eee;\n\t}\n\t.tab-container .tab-title-container .tab-title.active {\n\t    color: #ef4238;\n\t    border-bottom-color: #ef4238;\n\t}\n\t.tab-container .tab-title-container .tab-title {\n\t    cursor: pointer;\n\t    float: left;\n\t    margin-right: 30px;\n\t    margin-bottom: -2px;\n\t    padding-bottom: 10px;\n\t    font-size: 18px;\n\t    color: #333;\n\t    line-height: 100%;\n\t    border-bottom: 2px solid transparent;\n\t}\n\t.tab-container .tab-title-container .tab-title.tab-disabled {\n\t    color: #999;\n\t    cursor: not-allowed;\n\t}\n\n\t.tab-container .tab-content-container .tab-content.active {\n\t    display: block;\n\t}\n\t.tab-container .tab-content-container .tab-content {\n\t    display: none;\n\t}\n\n\t.tab-desc {\n\t    margin-top: 40px;\n\t}\n\t.module {\n\t    position: relative;\n\t    margin-bottom: 60px;\n\t}\n\t.module .mod-title h3 {\n\t    display: inline-block;\n\t    margin: 0;\n\t    padding: 0;\n\t    font-weight: 400;\n\t    font-size: 18px;\n\t    color: #333;\n\t    line-height: 18px;\n\t}\n\t.module .mod-title h3:before {\n\t    float: left;\n\t    content: \"\";\n\t    display: inline-block;\n\t    width: 4px;\n\t    height: 18px;\n\t    margin-right: 6px;\n\t    background-color: #ef4238;\n\t}\n\t.module .mod-content {\n\t    margin-top: 20px;\n\t    color: #333;\n\t}\n\t.tab-desc .dra {\n\t    font-size: 14px;\n\t    line-height: 26px;\n\t}\n\t.module .mod-title .more {\n\t    float: right;\n\t    cursor: pointer;\n\t    font-size: 14px;\n\t    color: #999;\n\t    padding-right: 14px;\n\t    background:  no-repeat 100%;\n\t}\n\t.clearfix:after, .clearfix:before {\n\t    content: \" \";\n\t    display: table;\n\t}\n\t.tab-desc .celebrity-container .celebrity-group:first-child {\n    margin-left: 0;\n\t}\n\t.tab-desc .celebrity-container .celebrity-group {\n\t    float: left;\n\t    margin-left: 45px;\n\t}\n\t.celebrity-container .celebrity-type {\n    \tmargin-bottom: 16px;\n\t}\n\t.celebrity-container .celebrity-list {\n    \tmargin-left: -20px;\n\t}\n\t.tab-desc .celebrity-container .celebrity-group .celebrity {\n    margin-bottom: 0;\n\t}\n\t.celebrity-container .celebrity {\n\t    float: left;\n\t    width: 128px;\n\t    margin-left: 20px;\n\t    margin-bottom: 20px;\n\t    text-overflow: ellipsis;\n\t    white-space: nowrap;\n\t}\n\t.celebrity-container .celebrity .portrait {\n\t    margin-bottom: 6px;\n\t    width: 128px;\n\t    height: 170px;\n\t    overflow: hidden;\n\t}\n\t.celebrity-container .celebrity .portrait img {\n\t    width: 128px;\n\t    height: 170px;\n\t}\n\t.default-img {\n\t    /* background-image: url(\"../images/movies/banner.jpg\") top no-repeat; */\n\t    background-position: 50%;\n\t    background-size: 68px 62px;\n\t    background-repeat: no-repeat;\n\t}\n\t.celebrity-container .celebrity .name {\n\t    margin-top: 8px;\n\t    line-height: 1.2;\n\t    color: #333;\n\t}\n\t.celebrity-container .celebrity .name, .celebrity-container .celebrity .role {\n\t    display: inline-block;\n\t    width: 128px;\n\t    text-align: center;\n\t    padding-bottom: 1px;\n\t    margin-bottom: -1px;\n\t    text-overflow: ellipsis;\n\t    overflow: hidden;\n\t    white-space: nowrap;\n\t}\n\t.banner2 .wrapper .celeInfo-right {\n\t    margin-top: 4px;\n\t}\n\t.staringPeople{\n\t\theight: 300px;\n\t}\n\t.comment-container .main2 {\n   \t \tmargin-left: 70px;\n\t}\n\t.comment-container {\n    \tmargin-top: 20px;\n\t}\n\t.comment-container .portrait-container {\n\t    margin-right: 20px;\n\t    float: left;\n\t    position: relative;\n\t    width: 50px;\n\t    height: 50px;\n\t}\n\t.comment-container .portrait {\n\t    border-radius: 50%;\n\t    overflow: hidden;\n\t    width: 50px;\n\t    height: 50px;\n\t}\n\t.comment-container .portrait img {\n    \twidth: 50px;\n\t}\n\t.comment-container .portrait-container .level-1-icon {\n\t    display: inline-block;\n\t    width: 20px;\n\t    height: 20px;\n\t    position: absolute;\n\t    bottom: -2px;\n\t    right: -2px;\n\t    \n\t}\n\t.comment-container .main2-header {\n\t    position: relative;\n\t    font-size: 16px;\n\t}\n\t.comment-container .main2-header .user {\n    \tmargin-top: 2px;\n\t}\n\t.comment-container .main2-header .name {\n\t    vertical-align: middle;\n\t    color: #333;\n\t}\n\t.comment-container .main2-header .tag {\n\t    display: inline-block;\n\t    width: 14px;\n\t    height: 14px;\n\t    border: 1px solid #7cc6f9;\n\t    border-radius: 2px;\n\t    color: #7cc6f9;\n\t    font-size: 12px;\n\t    line-height: 14px;\n\t    text-align: center;\n\t}\n\t.comment-container .main2-header .time {\n\t    margin-top: 4px;\n\t    color: #999;\n\t}\n\t.comment-container .main2-header .time {\n    margin-top: 4px;\n    color: #999;\n\t}\t\n\t.comment-container .main2-header .score-star {\n\t    display: inline-block;\n\t}\n\t.score-star li {\n\t    float: left;\n\t    height: 16px;\n\t}\n\t.comment-container .approve {\n\t    position: absolute;\n\t    top: 20px;\n\t    right: 0;\n\t}\n\t.comment-container .approve .approve-icon {\n    cursor: pointer;\n    margin-top: -6px;\n    margin-right: 8px;\n    vertical-align: middle;\n\t}\n\t.like-icon, i.approve-icon {\n\t    display: inline-block;\n\t    width: 16px;\n\t    height: 16px;\n\t   \n\t}\n\t.comment-container .approve .num {\n    font-size: 14px;\n    color: #999;\n\t}\n\t.clearfix:after {\n    clear: both;\n\t}\n\t.clearfix:after, .clearfix:before {\n\t    content: \" \";\n\t    display: table;\n\t}\n\t.comment-container .comment-content {\n    margin-top: 20px;\n    padding-bottom: 30px;\n    border-bottom: 1px solid #e5e5e5;\n    color: #666;\n    line-height: 26px;\n    font-size: 14px;\n\t}\n\t.comment-entry {\n\t    cursor: pointer;\n\t    position: absolute;\n\t    top: -10px;\n\t    right: 0;\n\t    display: block;\n\t    height: 30px;\n\t    padding: 0 10px;\n\t    border-radius: 15px;\n\t    border: 1px solid #ef4238;\n\t    text-align: center;\n\t    font-size: 14px;\n\t    line-height: 30px;\n\t    color: #ef4238;\n\t}\n\t.comment-entry:hover {\n\t\ttext-decoration: none;\n\t\tcolor: #fff;\n\t\tbackground-color: #ef4238;\n\t}\n\t.deleteCom{\n\t\tcursor: pointer;\n\t\theight: 30px !important;\n\t\twidth: 67px;\n\t\tpadding: 6 10px;\n\t\tborder-radius: 15px;\n\t\tborder: 1px solid #ef4238;\n\t\ttext-align: center;\n\t\tfont-size: 14px;\n\t\tline-height: 30px;\n\t\tcolor: #ef4238;\n\t\tmargin-left: 80px;\n\t}\n\t.deleteCom:hover{\n\t\tborder: 1px solid #ef4238;\n\t\tbackground-color: #ef4238;\n\t\tcolor: #fff;\n\t\ttext-decoration: none;\n\t}\n\t.updateBtn{\n\t\tcursor: pointer;\n\t\theight: 30px !important;\n\t\twidth: 67px;\n\t\tfloat: left;\n\t\tpadding: 6 10px;\n\t\tborder-radius: 15px;\n\t\tborder: 1px solid #009688;\n\t\ttext-align: center;\n\t\tfont-size: 14px;\n\t\tline-height: 30px;\n\t\tcolor: #009688;\n\t}\n\t.updateBtn:hover{\n\t\tborder: 1px solid #009688;\n\t\tbackground-color: #009688;\n\t\tcolor: #fff;\n\t\ttext-decoration: none;\n\t}\n\t.commenttitle{\n\t\tmargin: 30px 0;\n\t\tfont-size: 18px;\n\t\ttext-align: center;\n\t}\n\t.username, .commenttime, .commentcontent{\n\t\twidth: 280px;\n\t}\n\t.usernametext, .commenttimetext, .commentcontenttext{\n\t\twidth: 100px !important;\t\n\t}\n"
  },
  {
    "path": "src/main/webapp/static/css/movieList.css",
    "content": ".movies-channel {\n\t    width: 1120px;\n\t    margin: auto;\n\t    overflow: hidden;\n\t}\n\t.tags-panel {\n\t    border: 1px solid #e5e5e5;\n\t    padding: 0 20px;\n\t    margin-top: 40px;\n\t}\n\t.tags-panel li, .tags-panel ul {\n\t    margin: 0;\n\t    padding: 0;\n\t    list-style-type: none;\n\t}\n\t.tags li.active {\n\t    background: #f34d41;\n\t    color: #fff;\n\t}\n\t.tags li.active a {\n    \tcolor: #fff;\n\t}\n\t.tags li a {\n\t\t\n\t    color: #333;\n\t    font-size: 14px;\n\t}\n\t.tags li {\n\t\t\n\t    border-radius: 14px;\n\t    padding: 3px 9px;\n\t    display: inline-block;\n\t    margin-left: 12px;\n\t}\n\t.tags-title {\n\t    height: 24px;\n\t    line-height: 24px;\n\t    float: left;\n\t    color: #999;\n\t    font-size: 14px;\n\t}\n\t.tags {\n    \tmargin-left: 40px!important;\n\t}\n\t.tags-line {\n\t    padding: 10px 0!important;\n\t}\n\n\t.tags-line-border {\n    \tborder-top: 1px dotted #e5e5e5;\n\t}\n\t.movies-panel {\n  \t  margin-top: 40px;\n  \t  margin-left: 30px;\n\t}\n\t.movies-sorter {\n    \toverflow: hidden;\n\t}\n\t.movies-sorter .cat-sorter {\n\t    float: left;\n\t    padding-left: 2px;\n\t}\n\t.movies-sorter ul {\n\t    margin: 0;\n\t    padding: 0;\n\t    list-style: none;\n\t}\n\t.movies-sorter li {\n\t    display: inline-block;\n\t    height: 20px;\n\t    line-height: 18px;\n\t    margin-right: 30px;\n\t}\n\t.sort-control-group {\n\t    cursor: pointer;\n\t    line-height: 16px;\n\t}\n\t\n\t.sort-radio {\n\t    background: url(\"../images/circle-white.jpg\") no-repeat;\n\t}\n\t.sort-radio-checked {\n    \tbackground: url(\"../images/circle-red.jpg\") no-repeat;\n\t}\n\t.sort-control {\n\t    display: inline-block;\n\t    vertical-align: top;\n\t    width: 20px;\n\t    height: 20px;\n\t    margin-right: 2px;\n\t}\n\t.sort-control-label {\n\t    font-size: 14px;\n\t    vertical-align: top;\n\t}\n\n\t.movie-item {\n\t    position: relative;\n\t    border: 1px solid #efefef;\n\t    margin: -1px;\n\t}\n\n\t.movie-poster {\n\t    background-color: #fcfcfc;\n\t    width: 160px;\n\t    height: 220px;\n\t    overflow: hidden;\n\t    position: relative;\n\t}\n\t.channel-action-sale {\n    \tbackground-color: #f34d41;\n\t}\n\t.channel-action {\n\t    position: absolute;\n\t    right: 5px;\n\t    bottom: 5px;\n\t    padding: 0 3px;\n\t    height: 18px;\n\t    line-height: 18px;\n\t    border-radius: 1px;\n\t}\n\t.channel-action a {\n\t    color: #fff;\n\t    font-size: 12px;\n\t    vertical-align: top;\n\t}\n\t.movie-ver {\n\t    position: absolute;\n\t    top: 4px;\n\t    left: -2px;\n\t    font-size: 12px;\n\t    color: #fff;\n\t}\n\t.channel-detail {\n\t    width: 160px;\n\t    white-space: nowrap;\n\t    overflow: hidden;\n\t    text-overflow: ellipsis;\n\t    text-align: center;\n\t    font-size: 16px;\n\t    color: #333;\n\t    margin-top: 10px;\n\t}\n\t.channel-detail a {\n    \tcolor: #333;\n\t}\n\t.channel-detail-orange, .channel-detail-prescore {\n    \tcolor: #ffb400;\n\t}\n\t.channel-detail-orange .integer {\n    \tfont-size: 18px;\n\t}\n\t.channel-detail-orange .fraction {\n    \tfont-size: 14px;\n\t}\n\n\t.movie-list li {\n    \tmargin: 0 28px 40px 0px;\n\t}\n\t.movie-item {\n\t    height: 220px;\n\t}"
  },
  {
    "path": "src/main/webapp/static/css/pay.css",
    "content": ".container{\n    display: block;\n    margin-bottom: 100px;\n    padding: 0;\n}\n.container .order-progress-bar{\n    height: 60px;\n    width: 100%;\n    margin: 40px 0;\n    text-align: center;\n}\n.container .order-progress-bar .step{\n    float: left;\n    width: 25%;\n}\n.container .order-progress-bar .step .step-num{\n    color: #fff;\n    font-size: 12px;\n    display: inline-block;\n    width: 16px;\n    height: 16px;\n    line-height: 16px;\n    border-radius: 10px;\n    text-align: center;\n    background-color: #ffd8d7;\n    position: relative;\n    top: 10px;\n}\n.container .order-progress-bar .first .bar{\n    border-left-color: transparent !important;\n}\n.container .order-progress-bar .last .bar{\n    border-right-color: transparent !important;\n}\n.container .order-progress-bar .step .bar{\n    width: 0;\n    height: 4px;\n    border-left: 150px solid #ffd8d7;\n    border-right: 150px solid #ffd8d7;\n}\n.container .order-progress-bar .done .step-num{\n    background-color: #f03d37;\n}\n.container .order-progress-bar .done .bar{\n    border-left: 150px solid #f03d37;\n    border-right: 150px solid #f03d37;\n}\n.container .order-progress-bar .step .step-next{\n    font-size: 14px;\n    color: #999;\n    display: inline-block;\n    margin-top: 10px;\n}\n\n\n\n\n\n\n.container .count-down-wrapper{\n    width: 100%;\n    height: 110px;\n    padding-top: 20px;\n    margin-bottom: 40px;\n    background-color: #fff3f3;\n}\n.container .count-down-wrapper .count-down{\n    padding-left: 55px;\n    min-height: 41px;\n    margin-left: 30px;\n    background: url(../images/time.jpg) no-repeat;\n    background-size: 50px 50px;\n    background-position: 0 10px;\n}\n.container .count-down-wrapper .count-down .time-left{\n    font-size: 16px;\n    color: #666;\n    margin-bottom: 4px;\n}\n.container .count-down-wrapper .count-down .time-left .minute, .second{\n    font-size: 32px;\n    color: #f03d37;\n    margin: 0 5px;\n}\n.container .count-down-wrapper .count-down .tip{\n    font-size: 14px;\n    color: #f03d37;\n}\n\n\n\n\n\n.container .warning{\n    font-size: 12px;\n    color: #666;\n    padding-left: 18px;\n    background: url(../images/warning.jpg) no-repeat;\n    background-size: 14px;\n    background-position-y: 2px;\n    margin-bottom: 8px;\n}\n.container .warning .attention{\n    color: #faaf00;\n}\n\n\n\n\n.container .order-table{\n    width: 100%;\n    border: 1px solid #e5e5e5;\n    border-spacing: 0;\n    margin-bottom: 60px;\n}\n.container .order-table thead{\n    background-color: #f7f7f7;\n}\n.container .order-table thead th{\n    font-size: 16px;\n    color: #333;\n    width: 25%;\n    padding: 14px 0;\n    font-weight: 400;\n    text-align: center;\n}\n.container .order-table tbody td{\n    text-align: center;\n    padding: 20px 0;\n    color: #333;\n}\n.container .order-table tbody td .hall{\n    display: inline-block;\n    font-size: 14px;\n    color: #424242;\n    font-weight: 700;\n    margin-right: 10px;\n    vertical-align: top;\n}\n.container .order-table tbody td .seats{\n    display: inline-block;\n    text-align: left;\n}\n.container .order-table tbody td .seats span{\n    font-size: 12px;\n    margin-right: 2px;\n}\n.container .order-table tbody td .seats i{\n    font-size: 16px;\n    font-style: normal;\n    margin: 0 2px;\n}\n.container .order-table tbody td .seats span.border{\n    border-left: 1px solid #e5e5e5;\n    padding-left: 5px;\n}\n.order-table tr{\n    border: 1px solid #ddd;\n}\n\n\n\n.container .right{\n    text-align: right;\n}\n.container .right .price-wrapper{\n    font-size: 14px;\n    color: #333;\n    margin-bottom: 17px;\n}\n.container .right .price-wrapper .price{\n    font-size: 36px;\n    color: #f03d37;\n}\n.container .right .pay-btn{\n    cursor: pointer;\n    display: inline-block;\n    width: 190px;\n    height: 42px;\n    line-height: 42px;\n    text-align: center;\n    color: #fff;\n    background-color: #f03d37;\n    border-radius: 100px;\n    -webkit-box-shadow: 0 2px 10px -2px #f03d37;\n    box-shadow: 0 2px 10px -2px #f03d37;\n}"
  },
  {
    "path": "src/main/webapp/static/css/paystatus.css",
    "content": ".container{\n    display: block;\n    margin-bottom: 100px;\n    padding: 0;\n}\n.container .order-progress-bar{\n    height: 60px;\n    width: 100%;\n    margin: 40px 0;\n    text-align: center;\n}\n.container .order-progress-bar .step{\n    float: left;\n    width: 25%;\n}\n.container .order-progress-bar .step .step-num{\n    color: #fff;\n    font-size: 12px;\n    display: inline-block;\n    width: 16px;\n    height: 16px;\n    line-height: 16px;\n    border-radius: 10px;\n    text-align: center;\n    background-color: #ffd8d7;\n    position: relative;\n    top: 10px;\n}\n.container .order-progress-bar .first .bar{\n    border-left-color: transparent !important;\n}\n.container .order-progress-bar .last .bar{\n    border-right-color: transparent !important;\n}\n.container .order-progress-bar .step .bar{\n    width: 0;\n    height: 4px;\n    border-left: 150px solid #ffd8d7;\n    border-right: 150px solid #ffd8d7;\n}\n.container .order-progress-bar .done .step-num{\n    background-color: #f03d37;\n}\n.container .order-progress-bar .done .bar{\n    border-left: 150px solid #f03d37;\n    border-right: 150px solid #f03d37;\n}\n.container .order-progress-bar .step .step-next{\n    font-size: 14px;\n    color: #999;\n    display: inline-block;\n    margin-top: 10px;\n}\n\n\n\n\n.container .warning{\n    font-size: 12px;\n    color: #666;\n    padding-left: 18px;\n    background: url(../images/warning.jpg) no-repeat;\n    background-position-x: 900px;\n    background-size: 14px;\n    background-position-y: 2px;\n    margin-bottom: 8px;\n}\n.container .warning .attention{\n    color: #faaf00;\n}\n\n\n\n\n.main-paystatus{\n    text-align: center;\n    padding: 100px 0;\n    margin-top: 30px;\n    margin-bottom: 30px;\n    background-color: rgb(228, 253, 235);\n}\n.main-paystatus img{\n    width: 120px;\n    height: 120px;\n}\n.main-paystatus .statustext{\n    margin-top: 20px;\n    font-size: 24px;\n    color: rgb(0, 148, 0);\n    font-weight: 700;\n}\n\n\n\n\n\n\n\n.container .right{\n    text-align: right;\n}\n.container .right .price-wrapper{\n    font-size: 14px;\n    color: #333;\n    margin-bottom: 17px;\n}\n.container .right .price-wrapper .price{\n    font-size: 36px;\n    color: #f03d37;\n}\n.container .right .pay-btn{\n    cursor: pointer;\n    display: inline-block;\n    width: 190px;\n    height: 42px;\n    line-height: 42px;\n    text-align: center;\n    color: #fff;\n    background-color: #f03d37;\n    border-radius: 100px;\n    -webkit-box-shadow: 0 2px 10px -2px #f03d37;\n    box-shadow: 0 2px 10px -2px #f03d37;\n}"
  },
  {
    "path": "src/main/webapp/static/css/selectSeat.css",
    "content": ".banner2 .wrapper {\n\t/*background: #000;*/\n\twidth: 1200px;\n\tmargin: 0 auto;\n\theight: 320px;\n\tposition: relative;\n\ttop: 70px;\n}\t\n.banner2 {\n\twidth: 100%;\n\tmin-width: 1200px;\n\tbackground: #392f59 url(\"../images/movies/banner.png\") no-repeat 50%;\n}\n.banner2 .wrapper .cinema-main {\n\tposition: relative;\n\tfloat: left;\n\tmax-width: 600px;\n}\n.banner2 .wrapper .cinema-left {\n\twidth: 360px;\n\tfloat: left;\n\toverflow: hidden;\n\tz-index: 9;\n}\n.cinema-left .avatar-shadow {\n\twidth: 300px;\n\theight: 300px;\n\tbackground-size: 300px 50px;\n\tposition: relative;\n}\n.cinema-left .avatar-shadow .avatar {\n\tborder: 4px solid #fff;\n\theight: 292px;\n\twidth: 292px;\n}\n\n.cinema-left .avatar-shadow .avatar-num {\n\tposition: absolute;\n\tleft: 4px;\n\tbottom: 5px;\n\twidth: 292px;\n\tline-height: 32px;\n\tbackground-color: rgba(0,0,0,.6);\n\tcolor: #fff;\n\tfont-size: 14px;\n\ttext-align: center;\n}\n.banner2 .wrapper .cinema-brief-container {\n\tcolor: #fff;\n}\n.banner2 .wrapper .cinema-brief-container .name {\n\tmargin: 0;\n\tfont-size: 26px;\n\tmargin-bottom: 9px;\n\tfont-weight: 400;\n}\n.text-ellipsis {\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n.banner2 .wrapper .cinema-brief-container .address, .banner2 .wrapper .cinema-brief-container .telphone {\n\tfont-size: 14px;\n\tmargin-bottom: 6px;\n}\n.banner2 .wrapper .cinema-brief-container .telphone {\n\tmargin-bottom: 20px;\n}\n.banner2 .wrapper .cinema-brief-container .features-group {\n\tposition: relative;\n}\n.banner2 .wrapper .cinema-brief-container .features-group .group-title {\n\tfont-size: 14px;\n\tmargin-bottom: 5px;\n\toverflow: hidden;\n\twidth: 410px;\n}\n.banner2 .wrapper .cinema-brief-container .features-group .group-title:after {\n\tborder-top: 1px solid hsla(0,0%,100%,.7);\n\tdisplay: block;\n\tcontent: \"\";\n\tposition: relative;\n\ttop: -10px;\n\tleft: 70px;\n}\n.banner2 .wrapper .cinema-brief-container .features-group .feature {\n\tfont-size: 12px;\n\tmargin-bottom: 2px;\n\tposition: relative;\n\tmin-height: 22px;\n\tline-height: 23px;\n\t-webkit-transform-origin: 0;\n\t-ms-transform-origin: 0;\n\ttransform-origin: 0;\n\t-webkit-transform: scale(.8);\n\t-ms-transform: scale(.8);\n\ttransform: scale(.8);\n}\n.banner2 .wrapper .cinema-brief-container .features-group .feature .tag {\n\tdisplay: inline-block;\n\tborder: 1px solid hsla(0,0%,100%,.6);\n\tborder-radius: 2px;\n\tmin-width: 60px;\n\theight: 22px;\n\tline-height: 23px;\n\ttext-align: center;\n}\n.banner2 .wrapper .cinema-brief-container .features-group .feature .desc {\n\tdisplay: inline-block;\n\tmax-width: 438px;\n\tmargin-left: 5px;\n\tvertical-align: middle;\n}\n.movie-list-container {\n\theight: 280px;\n\tpadding: 22px 5px;\n\t-webkit-box-sizing: border-box;\n\tbox-sizing: border-box;\n\toverflow: hidden;\n\t-webkit-box-shadow: inset 0 0 100px 80px #ededed;\n\tbox-shadow: inset 0 0 100px 80px #ededed;\n\tposition: relative;\n}\n.movie-list-container .movie-list {\n\twhite-space: nowrap;\n\tposition: relative;\n\tdisplay: table;\n\tleft: 60;\n\t-webkit-transition: left .2s ease;\n\ttransition: left .2s ease;\n}\n.movie-list-container .movie.active {\n\tmargin: 0 16px;\n\t-webkit-transform: scale(1);\n\t-ms-transform: scale(1);\n\ttransform: scale(1);\n\tborder-color: #fd8e84;\n}\n.movie-list-container .movie {\n\twidth: 162px;\n\theight: 227px;\n\tborder: 4px solid #fff;\n\t-webkit-box-shadow: 0 1px 3px 0 hsla(0,0%,66%,.5);\n\tbox-shadow: 0 1px 3px 0 hsla(0,0%,66%,.5);\n\tdisplay: inline-block;\n\t-webkit-transform-origin: 50%;\n\t-ms-transform-origin: 50%;\n\ttransform-origin: 50%;\n\t-webkit-transform: scale(.82);\n\t-ms-transform: scale(.82);\n\ttransform: scale(.82);\n\t-webkit-transition: -webkit-transform .1s;\n\ttransition: -webkit-transform .1s;\n\ttransition: transform .1s;\n\ttransition: transform .1s,-webkit-transform .1s;\n\tword-spacing: 0;\n}\n.movie-list-container .movie-list {\n\twhite-space: nowrap;\n\tposition: relative;\n\tdisplay: table;\n\tleft: 20;\n\ttop:-17px;\n\tmargin-left:60px;\n}\n.movie-list-container .movie img {\n\twidth: 100%;\n\theight: 100%;\n}\n.movie-list-container .pointer {\n\tposition: absolute;\n\tdisplay: block;\n\tcontent: \"\";\n\tbottom: -23px;\n\tleft: 71px;\n\tborder-style: solid;\n\tborder-width: 11px 14px;\n\tborder-color: transparent transparent #fff;\n}\t\n.show-list.active {\n\tdisplay: block;\n}\n.show-list {\n\tdisplay: none;\n}\n.show-list .movie-info {\n\tmargin-top: 20px;\n\tborder-bottom: 1px solid #e5e5e5;\n}\n.show-list .movie-info .movie-name {\n\tdisplay: inline-block;\n\tmargin: 0 20px 20px 0;\n\tfont-size: 26px;\n\tfont-weight: 400;\n\tcolor: #333;\n}\nth {\n\tfont-weight: bold;\n\ttext-align: -internal-center;\n}\n\ntd, th {\n\tdisplay: table-cell;\n\tvertical-align: inherit;\n}\ntr {\n\tdisplay: table-row;\n\tvertical-align: inherit;\n\tborder-color: inherit;\n}\n\nh3 {\n\tdisplay: block;\n\tfont-size: 1.17em;\n\tmargin-block-start: 1em;\n\tmargin-block-end: 1em;\n\tmargin-inline-start: 0px;\n\tmargin-inline-end: 0px;\n\tfont-weight: bold;\n}\ntable {\n\tdisplay: table;\n\tborder-collapse: separate;\n\tborder-spacing: 2px;\n\tborder-color: grey;\n}\ntbody {\n\tdisplay: table-row-group;\n\tvertical-align: middle;\n\tborder-color: inherit;\n}\n.show-list .plist tbody tr {\n\theight: 82px;\n}\n.show-list .movie-info .score {\n\tdisplay: inline-block;\n\tfont-size: 24px;\n\tcolor: #faaf00;\n}\n.show-list .movie-info .movie-desc>div {\n\tdisplay: inline-block;\n\tfont-size: 14px;\n\tcolor: #151515;\n\tmargin-bottom: 20px;\n\tmargin-right: 40px;\n}\n.show-list .movie-info .movie-desc .key {\n\tcolor: #999;\n}\n.show-list .show-date {\n\tpadding: 30px 0;\n\tfont-size: 14px;\n\tcolor: #999;\n}\n.show-list .show-date {\n\tpadding: 30px 0;\n\tfont-size: 14px;\n\tcolor: #999;\n}\n.show-list .show-date .date-item.active {\n\tcolor: #fff;\n\tbackground-color: #f03d37;\n}\n.show-list .show-date .date-item {\n\tdisplay: inline-block;\n\tbackground-color: transparent;\n\tborder-radius: 100px;\n\tcolor: #333;\n\tpadding: 2px 10px;\n\tmargin-left: 12px;\n\tcursor: default;\n}\n.show-list .show-date {\n\tpadding: 30px 0;\n\tfont-size: 14px;\n\tcolor: #999;\n}\n.show-list .plist-container.active {\n\tdisplay: block;\n}\n.show-list .plist-container {\n\tdisplay: none;\n}\n.show-list .plist {\n\twidth: 100%;\n\tborder: none;\n\tborder-spacing: 0;\n}\n.show-list .plist thead {\n\tbackground-color: #f7f7f7;\n\tcolor: #333;\n\tfont-size: 16px;\n\tpadding: 18px 0;\n}\n.show-list .plist thead th {\npadding: 16px 0;\n}\n.show-list .plist tbody td {\n\ttext-align: center;\n\twidth: 20%;\n}\n.show-list .plist tbody .begin-time {\n\tfont-size: 18px;\n\tcolor: #333;\n\tfont-weight: 700;\n}\n.show-list .plist tbody .sell-price {\n\tfont-size: 18px;\n\tcolor: #f03d37;\n\tfont-weight: 700;\n}\n.stonefont {\n\tfont-family: stonefont;\n}\n.show-list .plist tbody .sell-price:before {\n\tcontent: \"\\FFE5\";\n\tfont-size: 12px;\n}\n.show-list .plist tbody .buy-btn.normal {\n\t-webkit-box-shadow: 0 2px 10px -2px #f03d37;\n\tbox-shadow: 0 2px 10px -2px #f03d37;\n}\n.show-list .plist tbody .buy-btn {\n\tdisplay: inline-block;\n\twidth: 80px;\n\theight: 30px;\n\tcolor: #fff;\n\tbackground-color: #f03d37;\n\tfont-size: 14px;\n\tline-height: 30px;\n\tborder-radius: 100px;\n\ttext-align: center;\n}\n.show-list .plist thead th {\n    padding: 16px 70px;\n}"
  },
  {
    "path": "src/main/webapp/static/css/style2.css",
    "content": "/*定义css变量*/\n:root{ \n\t--mywidth: 1420px;\n\t--myheight: 440px;\n}\n\n*{\n\tmargin: 0;\n\tpadding: 0;\n}\nhtml,body{\n\twidth: 100%;\n\theight: 100%;\n}\nbody{\n\tbackground-color: #1F1F1F;\n}\nul{\n\tlist-style: none;\n}\n.content{\n\twidth: 100%;\n\theight: 100%;\n\tdisplay: flex;\n    justify-content: center;\n    align-items: center;\n}\n.a-content{\n\tborder: 1px solid rgba(0,0,0,0.1);\n    border-radius:20px;\n    -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);\n    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);\n    position: relative;\n}\n.a-content:before{\n    content: '';\n    width: 500px;\n    height: 300px;\n    left: 35px;\n    top: 19px;\n    z-index:-1;\n    position:absolute;\n    border-radius:20px;\n    border: 1px solid rgba(0,0,0, 0.1);\n    background: rgba(0, 0, 0, 0.0);\n    -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);\n    box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);\n    -webkit-transform: translate(-5%,-5%);\n    transform:translate(-5%,-5%);\n\t-ms-transform:translate(-5%,-5%);\n\t-moz-transform:translate(-5%,-5%);\n\t-o-transform:translate(-5%,-5%);\n}\n.a-content:after{\n    content: '';\n    position:absolute;\n    top:-25px; \n    left: 25%;\n    width: 270px;\n    height: 40px;\n    background: -webkit-gradient(linear, 555% 20%, 0% 92%, from(rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 0.0)), color-stop(.1,rgba(0, 0, 0, 0.2)));\n    border-left: 1px dashed rgba(0, 0, 0, 0.1);\n    border-right: 1px dashed rgba(0, 0, 0, 0.1);\n    -webkit-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.2);\n    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.2);\n\tdisplay: none;\n}\n.carousel-content{\n\twidth: var(--mywidth);\n\theight: var(--myheight);\n\tposition: relative;\n\toverflow: hidden;\n\tborder-radius:10px;\n}\n.carousel{\n\theight: var(--myheight);\n\tposition: absolute;\n}\n.carousel li{\n\tfloat: left;\n}\n.carousel li,.carousel li img{\n\twidth: var(--mywidth);\n\theight: var(--myheight);\n}\n.img-index{\n\tposition: absolute;\n    bottom: 8px;\n    width: 100%;\n    display: flex;\n    justify-content: center;\n}\n.img-index li{\n\tfloat: left;\n    width: 18px;\n    height: 18px;\n    line-height: 18px;\n    text-align: center;\n    border-radius: 10px;\n    background-color: rgba(0,0,0,0.2);\n    font-size: 12px;\n    cursor: pointer;\n    margin: 0 3px;\n    color: #fff;\n}\n.img-index li.js_index,.img-index li:hover{\n\tbackground-color: rgba(0,0,0,0.7);\n}\n.carousel-prev,.carousel-next{\n\tposition: absolute;\n\tdisplay: inline-block;\n\ttop: 45%;\n\tcursor: pointer;\n    display: none;\n}\n.carousel-prev{\n\tleft: 0;\n}\n.carousel-next{\n\tright: 0;\n}"
  },
  {
    "path": "src/main/webapp/static/js/Api.js",
    "content": "var urlHead = \"http:///edy45u.\";\n\nvar urlFoot = \"natappfree.cc\";\n\nvar url = urlHead.toString() + urlFoot.toString();"
  },
  {
    "path": "src/main/webapp/static/js/classie.js",
    "content": "/*!\n * classie v1.0.1\n * class helper functions\n * from bonzo https://github.com/ded/bonzo\n * MIT license\n * \n * classie.has( elem, 'my-class' ) -> true/false\n * classie.add( elem, 'my-new-class' )\n * classie.remove( elem, 'my-unwanted-class' )\n * classie.toggle( elem, 'my-class' )\n */\n\n/*jshint browser: true, strict: true, undef: true, unused: true */\n/*global define: false, module: false */\n\n( function( window ) {\n\n'use strict';\n\n// class helper functions from bonzo https://github.com/ded/bonzo\n\nfunction classReg( className ) {\n  return new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\");\n}\n\n// classList support for class management\n// altho to be fair, the api sucks because it won't accept multiple classes at once\nvar hasClass, addClass, removeClass;\n\nif ( 'classList' in document.documentElement ) {\n  hasClass = function( elem, c ) {\n    return elem.classList.contains( c );\n  };\n  addClass = function( elem, c ) {\n    elem.classList.add( c );\n  };\n  removeClass = function( elem, c ) {\n    elem.classList.remove( c );\n  };\n}\nelse {\n  hasClass = function( elem, c ) {\n    return classReg( c ).test( elem.className );\n  };\n  addClass = function( elem, c ) {\n    if ( !hasClass( elem, c ) ) {\n      elem.className = elem.className + ' ' + c;\n    }\n  };\n  removeClass = function( elem, c ) {\n    elem.className = elem.className.replace( classReg( c ), ' ' );\n  };\n}\n\nfunction toggleClass( elem, c ) {\n  var fn = hasClass( elem, c ) ? removeClass : addClass;\n  fn( elem, c );\n}\n\nvar classie = {\n  // full names\n  hasClass: hasClass,\n  addClass: addClass,\n  removeClass: removeClass,\n  toggleClass: toggleClass,\n  // short names\n  has: hasClass,\n  add: addClass,\n  remove: removeClass,\n  toggle: toggleClass\n};\n\n// transport\nif ( typeof define === 'function' && define.amd ) {\n  // AMD\n  define( classie );\n} else if ( typeof exports === 'object' ) {\n  // CommonJS\n  module.exports = classie;\n} else {\n  // browser global\n  window.classie = classie;\n}\n\n})( window );"
  },
  {
    "path": "src/main/webapp/static/js/echarts.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\nfunction find(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    for (var i = 0, len = obj.length; i < len; i++) {\n        if (cb.call(context, obj[i], i, obj)) {\n            return obj[i];\n        }\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\nfunction concatArray(a, b) {\n    var newArray = new a.constructor(a.length + b.length);\n    for (var i = 0; i < a.length; i++) {\n        newArray[i] = a[i];\n    }\n    var offset = a.length;\n    for (i = 0; i < b.length; i++) {\n        newArray[i + offset] = b[i];\n    }\n    return newArray;\n}\n\n\nfunction noop() {}\n\n\nvar zrUtil = (Object.freeze || Object)({\n\t$override: $override,\n\tclone: clone,\n\tmerge: merge,\n\tmergeAll: mergeAll,\n\textend: extend,\n\tdefaults: defaults,\n\tcreateCanvas: createCanvas,\n\tgetContext: getContext,\n\tindexOf: indexOf,\n\tinherits: inherits,\n\tmixin: mixin,\n\tisArrayLike: isArrayLike,\n\teach: each$1,\n\tmap: map,\n\treduce: reduce,\n\tfilter: filter,\n\tfind: find,\n\tbind: bind,\n\tcurry: curry,\n\tisArray: isArray,\n\tisFunction: isFunction$1,\n\tisString: isString,\n\tisObject: isObject$1,\n\tisBuiltInObject: isBuiltInObject,\n\tisTypedArray: isTypedArray,\n\tisDom: isDom,\n\teqNaN: eqNaN,\n\tretrieve: retrieve,\n\tretrieve2: retrieve2,\n\tretrieve3: retrieve3,\n\tslice: slice,\n\tnormalizeCssArray: normalizeCssArray,\n\tassert: assert$1,\n\ttrim: trim,\n\tsetAsPrimitive: setAsPrimitive,\n\tisPrimitive: isPrimitive,\n\tcreateHashMap: createHashMap,\n\tconcatArray: concatArray,\n\tnoop: noop\n});\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\nfunction set(out, a, b) {\n    out[0] = a;\n    out[1] = b;\n    return out;\n}\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\nvar length = len; // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\nvar lengthSquare = lenSquare;\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction mul(out, v1, v2) {\n    out[0] = v1[0] * v2[0];\n    out[1] = v1[1] * v2[1];\n    return out;\n}\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction div(out, v1, v2) {\n    out[0] = v1[0] / v2[0];\n    out[1] = v1[1] / v2[1];\n    return out;\n}\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction dot(v1, v2) {\n    return v1[0] * v2[0] + v1[1] * v2[1];\n}\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction negate(out, v) {\n    out[0] = -v[0];\n    out[1] = -v[1];\n    return out;\n}\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\nfunction lerp(out, v1, v2, t) {\n    out[0] = v1[0] + t * (v2[0] - v1[0]);\n    out[1] = v1[1] + t * (v2[1] - v1[1]);\n    return out;\n}\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n\nvar vector = (Object.freeze || Object)({\n\tcreate: create,\n\tcopy: copy,\n\tclone: clone$1,\n\tset: set,\n\tadd: add,\n\tscaleAndAdd: scaleAndAdd,\n\tsub: sub,\n\tlen: len,\n\tlength: length,\n\tlenSquare: lenSquare,\n\tlengthSquare: lengthSquare,\n\tmul: mul,\n\tdiv: div,\n\tdot: dot,\n\tscale: scale,\n\tnormalize: normalize,\n\tdistance: distance,\n\tdist: dist,\n\tdistanceSquare: distanceSquare,\n\tdistSquare: distSquare,\n\tnegate: negate,\n\tlerp: lerp,\n\tapplyTransform: applyTransform,\n\tmin: min,\n\tmax: max\n});\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\nfunction isMiddleOrRightButtonOnMouseUpDown(e) {\n    return e.which === 2 || e.which === 3;\n}\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\nfunction clone$2(a) {\n    var b = create$1();\n    copy$1(b, a);\n    return b;\n}\n\nvar matrix = (Object.freeze || Object)({\n\tcreate: create$1,\n\tidentity: identity,\n\tcopy: copy$1,\n\tmul: mul$1,\n\ttranslate: translate,\n\trotate: rotate,\n\tscale: scale$1,\n\tinvert: invert,\n\tclone: clone$2\n});\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssAngle(i) {  // Clamp to integer 0 .. 360.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 360 ? 360 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction lerpNumber(a, b, p) {\n    return a + (b - a) * p;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {Array.<number>} rgba\n * @return {Array.<number>} hsla\n */\nfunction rgba2hsla(rgba) {\n    if (!rgba) {\n        return;\n    }\n\n    // RGB from 0 to 255\n    var R = rgba[0] / 255;\n    var G = rgba[1] / 255;\n    var B = rgba[2] / 255;\n\n    var vMin = Math.min(R, G, B); // Min. value of RGB\n    var vMax = Math.max(R, G, B); // Max. value of RGB\n    var delta = vMax - vMin; // Delta RGB value\n\n    var L = (vMax + vMin) / 2;\n    var H;\n    var S;\n    // HSL results from 0 to 1\n    if (delta === 0) {\n        H = 0;\n        S = 0;\n    }\n    else {\n        if (L < 0.5) {\n            S = delta / (vMax + vMin);\n        }\n        else {\n            S = delta / (2 - vMax - vMin);\n        }\n\n        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;\n        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;\n        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;\n\n        if (R === vMax) {\n            H = deltaB - deltaG;\n        }\n        else if (G === vMax) {\n            H = (1 / 3) + deltaR - deltaB;\n        }\n        else if (B === vMax) {\n            H = (2 / 3) + deltaG - deltaR;\n        }\n\n        if (H < 0) {\n            H += 1;\n        }\n\n        if (H > 1) {\n            H -= 1;\n        }\n    }\n\n    var hsla = [H * 360, S, L];\n\n    if (rgba[3] != null) {\n        hsla.push(rgba[3]);\n    }\n\n    return hsla;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction toHex(color) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);\n    }\n}\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\nfunction fastLerp(normalizedValue, colors, out) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    out = out || [];\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = colors[leftIndex];\n    var rightColor = colors[rightIndex];\n    var dv = value - leftIndex;\n    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));\n    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));\n    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));\n    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));\n\n    return out;\n}\n\n/**\n * @deprecated\n */\nvar fastMapToColor = fastLerp;\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\nfunction lerp$1(normalizedValue, colors, fullOutput) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = parse(colors[leftIndex]);\n    var rightColor = parse(colors[rightIndex]);\n    var dv = value - leftIndex;\n\n    var color = stringify(\n        [\n            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),\n            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),\n            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),\n            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))\n        ],\n        'rgba'\n    );\n\n    return fullOutput\n        ? {\n            color: color,\n            leftIndex: leftIndex,\n            rightIndex: rightIndex,\n            value: value\n        }\n        : color;\n}\n\n/**\n * @deprecated\n */\nvar mapToColor = lerp$1;\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyHSL(color, h, s, l) {\n    color = parse(color);\n\n    if (color) {\n        color = rgba2hsla(color);\n        h != null && (color[0] = clampCssAngle(h));\n        s != null && (color[1] = parseCssFloat(s));\n        l != null && (color[2] = parseCssFloat(l));\n\n        return stringify(hsla2rgba(color), 'rgba');\n    }\n}\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyAlpha(color, alpha) {\n    color = parse(color);\n\n    if (color && alpha != null) {\n        color[3] = clampCssFloat(alpha);\n        return stringify(color, 'rgba');\n    }\n}\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n\nvar color = (Object.freeze || Object)({\n\tparse: parse,\n\tlift: lift,\n\ttoHex: toHex,\n\tfastLerp: fastLerp,\n\tfastMapToColor: fastMapToColor,\n\tlerp: lerp$1,\n\tmapToColor: mapToColor,\n\tmodifyHSL: modifyHSL,\n\tmodifyAlpha: modifyAlpha,\n\tstringify: stringify\n});\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar zrLog = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            zrLog(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\nfunction $override$1(name, fn) {\n    methods$1[name] = fn;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, rich, textLineHeight, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            zrLog('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            zrLog('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                zrLog('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\nvar instances$1 = {};    // ZRender实例map索引\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.6';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    instances$1[zr.id] = zr;\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\nfunction dispose$1(zr) {\n    if (zr) {\n        zr.dispose();\n    }\n    else {\n        for (var key in instances$1) {\n            if (instances$1.hasOwnProperty(key)) {\n                instances$1[key].dispose();\n            }\n        }\n        instances$1 = {};\n    }\n\n    return this;\n}\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\nfunction getInstance(id) {\n    return instances$1[id];\n}\n\nfunction registerPainter(name, Ctor) {\n    painterCtors[name] = Ctor;\n}\n\nfunction delInstance(id) {\n    delete instances$1[id];\n}\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        delInstance(this.id);\n    }\n};\n\n\n\nvar zrender = (Object.freeze || Object)({\n\tversion: version$1,\n\tinit: init$1,\n\tdispose: dispose$1,\n\tgetInstance: getInstance,\n\tregisterPainter: registerPainter\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\nfunction compressBatches(batchA, batchB) {\n    var mapA = {};\n    var mapB = {};\n\n    makeMap(batchA || [], mapA);\n    makeMap(batchB || [], mapB, mapA);\n\n    return [mapToArray(mapA), mapToArray(mapB)];\n\n    function makeMap(sourceBatch, map$$1, otherMap) {\n        for (var i = 0, len = sourceBatch.length; i < len; i++) {\n            var seriesId = sourceBatch[i].seriesId;\n            var dataIndices = normalizeToArray(sourceBatch[i].dataIndex);\n            var otherDataIndices = otherMap && otherMap[seriesId];\n\n            for (var j = 0, lenj = dataIndices.length; j < lenj; j++) {\n                var dataIndex = dataIndices[j];\n\n                if (otherDataIndices && otherDataIndices[dataIndex]) {\n                    otherDataIndices[dataIndex] = null;\n                }\n                else {\n                    (map$$1[seriesId] || (map$$1[seriesId] = {}))[dataIndex] = 1;\n                }\n            }\n        }\n    }\n\n    function mapToArray(map$$1, isData) {\n        var result = [];\n        for (var i in map$$1) {\n            if (map$$1.hasOwnProperty(i) && map$$1[i] != null) {\n                if (isData) {\n                    result.push(+i);\n                }\n                else {\n                    var dataIndices = mapToArray(map$$1[i], true);\n                    dataIndices.length && result.push({seriesId: i, dataIndex: dataIndices});\n                }\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\nfunction fromPoints(points, min$$1, max$$1) {\n    if (points.length === 0) {\n        return;\n    }\n    var p = points[0];\n    var left = p[0];\n    var right = p[0];\n    var top = p[1];\n    var bottom = p[1];\n    var i;\n\n    for (i = 1; i < points.length; i++) {\n        p = points[i];\n        left = mathMin$3(left, p[0]);\n        right = mathMax$3(right, p[0]);\n        top = mathMin$3(top, p[1]);\n        bottom = mathMax$3(bottom, p[1]);\n    }\n\n    min$$1[0] = left;\n    min$$1[1] = top;\n    max$$1[0] = right;\n    max$$1[1] = bottom;\n}\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\nfunction asc(arr) {\n    arr.sort(function (a, b) {\n        return a - b;\n    });\n    return arr;\n}\n\n/**\n * Get precision\n * @param {number} val\n */\nfunction getPrecision(val) {\n    val = +val;\n    if (isNaN(val)) {\n        return 0;\n    }\n    // It is much faster than methods converting number to string as follows\n    //      var tmp = val.toString();\n    //      return tmp.length - 1 - tmp.indexOf('.');\n    // especially when precision is low\n    var e = 1;\n    var count = 0;\n    while (Math.round(val * e) / e !== val) {\n        e *= 10;\n        count++;\n    }\n    return count;\n}\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * BSD 3-Clause\n *\n * Copyright (c) 2010-2015, Michael Bostock\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, this\n *   list of conditions and the following disclaimer.\n *\n * * Redistributions in binary form must reproduce the above copyright notice,\n *   this list of conditions and the following disclaimer in the documentation\n *   and/or other materials provided with the distribution.\n *\n * * The name Michael Bostock may not be used to endorse or promote products\n *   derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @see <https://github.com/mbostock/d3/blob/master/src/arrays/quantile.js>\n * @see <http://en.wikipedia.org/wiki/Quantile>\n * @param {Array.<number>} ascArr\n */\nfunction quantile(ascArr, p) {\n    var H = (ascArr.length - 1) * p + 1;\n    var h = Math.floor(H);\n    var v = +ascArr[h - 1];\n    var e = H - h;\n    return e ? v + e * (ascArr[h] - v) : v;\n}\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\nfunction reformIntervals(list) {\n    list.sort(function (a, b) {\n        return littleThan(a, b, 0) ? -1 : 1;\n    });\n\n    var curr = -Infinity;\n    var currClose = 1;\n    for (var i = 0; i < list.length;) {\n        var interval = list[i].interval;\n        var close = list[i].close;\n\n        for (var lg = 0; lg < 2; lg++) {\n            if (interval[lg] <= curr) {\n                interval[lg] = curr;\n                close[lg] = !lg ? 1 - currClose : 1;\n            }\n            curr = interval[lg];\n            currClose = close[lg];\n        }\n\n        if (interval[0] === interval[1] && close[0] * close[1] !== 1) {\n            list.splice(i, 1);\n        }\n        else {\n            i++;\n        }\n    }\n\n    return list;\n\n    function littleThan(a, b, lg) {\n        return a.interval[lg] < b.interval[lg]\n            || (\n                a.interval[lg] === b.interval[lg]\n                && (\n                    (a.close[lg] - b.close[lg] === (!lg ? 1 : -1))\n                    || (!lg && littleThan(a, b, 1))\n                )\n            );\n    }\n}\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\nfunction isNumeric(v) {\n    return v - parseFloat(v) >= 0;\n}\n\n\nvar number = (Object.freeze || Object)({\n\tlinearMap: linearMap,\n\tparsePercent: parsePercent$1,\n\tround: round$2,\n\tasc: asc,\n\tgetPrecision: getPrecision,\n\tgetPrecisionSafe: getPrecisionSafe,\n\tgetPixelPrecision: getPixelPrecision,\n\tgetPercentWithPrecision: getPercentWithPrecision,\n\tMAX_SAFE_INTEGER: MAX_SAFE_INTEGER,\n\tremRadian: remRadian,\n\tisRadianAroundZero: isRadianAroundZero,\n\tparseDate: parseDate,\n\tquantity: quantity,\n\tnice: nice,\n\tquantile: quantile,\n\treformIntervals: reformIntervals,\n\tisNumeric: isNumeric\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\nfunction toCamelCase(str, upperCaseFirst) {\n    str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {\n        return group1.toUpperCase();\n    });\n\n    if (upperCaseFirst && str) {\n        str = str.charAt(0).toUpperCase() + str.slice(1);\n    }\n\n    return str;\n}\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTplSimple(tpl, param, encode) {\n    each$1(param, function (value, key) {\n        tpl = tpl.replace(\n            '{' + key + '}',\n            encode ? encodeHTML(value) : value\n        );\n    });\n    return tpl;\n}\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\nfunction capitalFirst(str) {\n    return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;\n}\n\nvar truncateText$1 = truncateText;\n\nvar getTextRect = getBoundingRect;\n\n\nvar format = (Object.freeze || Object)({\n\taddCommas: addCommas,\n\ttoCamelCase: toCamelCase,\n\tnormalizeCssArray: normalizeCssArray$1,\n\tencodeHTML: encodeHTML,\n\tformatTpl: formatTpl,\n\tformatTplSimple: formatTplSimple,\n\tgetTooltipMarker: getTooltipMarker,\n\tformatTime: formatTime,\n\tcapitalFirst: capitalFirst,\n\ttruncateText: truncateText$1,\n\tgetTextRect: getTextRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar box = boxLayout;\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\nfunction getAvailableSize(positionInfo, containerRect, margin) {\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var x = parsePercent$1(positionInfo.x, containerWidth);\n    var y = parsePercent$1(positionInfo.y, containerHeight);\n    var x2 = parsePercent$1(positionInfo.x2, containerWidth);\n    var y2 = parsePercent$1(positionInfo.y2, containerHeight);\n\n    (isNaN(x) || isNaN(parseFloat(positionInfo.x))) && (x = 0);\n    (isNaN(x2) || isNaN(parseFloat(positionInfo.x2))) && (x2 = containerWidth);\n    (isNaN(y) || isNaN(parseFloat(positionInfo.y))) && (y = 0);\n    (isNaN(y2) || isNaN(parseFloat(positionInfo.y2))) && (y2 = containerHeight);\n\n    margin = normalizeCssArray$1(margin || 0);\n\n    return {\n        width: Math.max(x2 - x - margin[1] - margin[3], 0),\n        height: Math.max(y2 - y - margin[0] - margin[2], 0)\n    };\n}\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\nfunction positionElement(el, positionInfo, containerRect, margin, opt) {\n    var h = !opt || !opt.hv || opt.hv[0];\n    var v = !opt || !opt.hv || opt.hv[1];\n    var boundingMode = opt && opt.boundingMode || 'all';\n\n    if (!h && !v) {\n        return;\n    }\n\n    var rect;\n    if (boundingMode === 'raw') {\n        rect = el.type === 'group'\n            ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0)\n            : el.getBoundingRect();\n    }\n    else {\n        rect = el.getBoundingRect();\n        if (el.needLocalTransform()) {\n            var transform = el.getLocalTransform();\n            // Notice: raw rect may be inner object of el,\n            // which should not be modified.\n            rect = rect.clone();\n            rect.applyTransform(transform);\n        }\n    }\n\n    // The real width and height can not be specified but calculated by the given el.\n    positionInfo = getLayoutRect(\n        defaults(\n            {width: rect.width, height: rect.height},\n            positionInfo\n        ),\n        containerRect,\n        margin\n    );\n\n    // Because 'tranlate' is the last step in transform\n    // (see zrender/core/Transformable#getLocalTransform),\n    // we can just only modify el.position to get final result.\n    var elPos = el.position;\n    var dx = h ? positionInfo.x - rect.x : 0;\n    var dy = v ? positionInfo.y - rect.y : 0;\n\n    el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]);\n}\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\nfunction sizeCalculable(option, hvIdx) {\n    return option[HV_NAMES[hvIdx][0]] != null\n        || (option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null);\n}\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent.prototype = {\n\n    constructor: Component,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar ORIGIN_METHOD = '\\0__throttleOriginMethod';\nvar RATE = '\\0__throttleRate';\nvar THROTTLE_TYPE = '\\0__throttleType';\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\nfunction createOrUpdate(obj, fnAttr, rate, throttleType) {\n    var fn = obj[fnAttr];\n\n    if (!fn) {\n        return;\n    }\n\n    var originFn = fn[ORIGIN_METHOD] || fn;\n    var lastThrottleType = fn[THROTTLE_TYPE];\n    var lastRate = fn[RATE];\n\n    if (lastRate !== rate || lastThrottleType !== throttleType) {\n        if (rate == null || !throttleType) {\n            return (obj[fnAttr] = originFn);\n        }\n\n        fn = obj[fnAttr] = throttle(\n            originFn, rate, throttleType === 'debounce'\n        );\n        fn[ORIGIN_METHOD] = originFn;\n        fn[THROTTLE_TYPE] = throttleType;\n        fn[RATE] = rate;\n    }\n\n    return fn;\n}\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\nfunction clear(obj, fnAttr) {\n    var fn = obj[fnAttr];\n    if (fn && fn[ORIGIN_METHOD]) {\n        obj[fnAttr] = fn[ORIGIN_METHOD];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: '矩形选择',\n                polygon: '圈选',\n                lineX: '横向选择',\n                lineY: '纵向选择',\n                keep: '保持选择',\n                clear: '清除选择'\n            }\n        },\n        dataView: {\n            title: '数据视图',\n            lang: ['数据视图', '关闭', '刷新']\n        },\n        dataZoom: {\n            title: {\n                zoom: '区域缩放',\n                back: '区域缩放还原'\n            }\n        },\n        magicType: {\n            title: {\n                line: '切换为折线图',\n                bar: '切换为柱状图',\n                stack: '切换为堆叠',\n                tiled: '切换为平铺'\n            }\n        },\n        restore: {\n            title: '还原'\n        },\n        saveAsImage: {\n            title: '保存为图片',\n            lang: ['右键另存为图片']\n        }\n    },\n    series: {\n        typeNames: {\n            pie: '饼图',\n            bar: '柱状图',\n            line: '折线图',\n            scatter: '散点图',\n            effectScatter: '涟漪散点图',\n            radar: '雷达图',\n            tree: '树图',\n            treemap: '矩形树图',\n            boxplot: '箱型图',\n            candlestick: 'K线图',\n            k: 'K线图',\n            heatmap: '热力图',\n            map: '地图',\n            parallel: '平行坐标图',\n            lines: '线图',\n            graph: '关系图',\n            sankey: '桑基图',\n            funnel: '漏斗图',\n            gauge: '仪表盘图',\n            pictorialBar: '象形柱图',\n            themeRiver: '主题河流图',\n            sunburst: '旭日图'\n        }\n    },\n    aria: {\n        general: {\n            withTitle: '这是一个关于“{title}”的图表。',\n            withoutTitle: '这是一个图表，'\n        },\n        series: {\n            single: {\n                prefix: '',\n                withName: '图表类型是{seriesType}，表示{seriesName}。',\n                withoutName: '图表类型是{seriesType}。'\n            },\n            multiple: {\n                prefix: '它由{seriesCount}个图表系列组成。',\n                withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType}，',\n                withoutName: '第{seriesId}个系列是一个{seriesType}，',\n                separator: {\n                    middle: '；',\n                    end: '。'\n                }\n            }\n        },\n        data: {\n            allData: '其数据是——',\n            partialData: '其中，前{displayCnt}项是——',\n            withName: '{name}的数据是{value}',\n            withoutName: '{value}',\n            separator: {\n                middle: '，',\n                end: ''\n            }\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\nfunction parseSVG(xml, opt) {\n    var parser = new SVGParser();\n    return parser.parse(xml, opt);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\nfunction getLayoutOnAxis(opt) {\n    var params = [];\n    var baseAxis = opt.axis;\n    var axisKey = 'axis0';\n\n    if (baseAxis.type !== 'category') {\n        return;\n    }\n    var bandWidth = baseAxis.getBandWidth();\n\n    for (var i = 0; i < opt.count || 0; i++) {\n        params.push(defaults({\n            bandWidth: bandWidth,\n            axisKey: axisKey,\n            stackId: STACK_PREFIX + i\n        }, opt));\n    }\n    var widthAndOffsets = doCalBarWidthAndOffset(params);\n\n    var result = [];\n    for (var i = 0; i < opt.count; i++) {\n        var item = widthAndOffsets[axisKey][STACK_PREFIX + i];\n        item.offsetCenter = item.offset + item.width / 2;\n        result.push(item);\n    }\n\n    return result;\n}\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* The `scaleLevels` references to d3.js. The use of the source\n* code of this file is also subject to the terms and consitions\n* of its license (BSD-3Clause, see <echarts/src/licenses/LICENSE-d3>).\n*/\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n// Steps from d3, see the license statement at the top of this file.\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import createGraphFromNodeEdge from './chart/helper/createGraphFromNodeEdge';\n/**\n * Create a muti dimension List structure from seriesModel.\n * @param  {module:echarts/model/Model} seriesModel\n * @return {module:echarts/data/List} list\n */\nfunction createList(seriesModel) {\n    return createListFromArray(seriesModel.getSource(), seriesModel);\n}\n\nvar dataStack$1 = {\n    isDimensionStacked: isDimensionStacked,\n    enableDataStack: enableDataStack,\n    getStackedDimension: getStackedDimension\n};\n\n/**\n * Create scale\n * @param {Array.<number>} dataExtent\n * @param {Object|module:echarts/Model} option\n */\nfunction createScale(dataExtent, option) {\n    var axisModel = option;\n    if (!Model.isInstance(option)) {\n        axisModel = new Model(option);\n        mixin(axisModel, axisModelCommonMixin);\n    }\n\n    var scale = createScaleByModel(axisModel);\n    scale.setExtent(dataExtent[0], dataExtent[1]);\n\n    niceScaleExtent(scale, axisModel);\n    return scale;\n}\n\n/**\n * Mixin common methods to axis model,\n *\n * Inlcude methods\n * `getFormattedLabels() => Array.<string>`\n * `getCategories() => Array.<string>`\n * `getMin(origin: boolean) => number`\n * `getMax(origin: boolean) => number`\n * `getNeedCrossZero() => boolean`\n * `setRange(start: number, end: number)`\n * `resetRange()`\n */\nfunction mixinAxisModelCommonMethods(Model$$1) {\n    mixin(Model$$1, axisModelCommonMixin);\n}\n\nvar helper = (Object.freeze || Object)({\n\tcreateList: createList,\n\tgetLayoutRect: getLayoutRect,\n\tdataStack: dataStack$1,\n\tcreateScale: createScale,\n\tmixinAxisModelCommonMethods: mixinAxisModelCommonMethods,\n\tcompleteDimensions: completeDimensions,\n\tcreateDimensions: createDimensions,\n\tcreateSymbol: createSymbol\n});\n\nvar EPSILON$3 = 1e-8;\n\nfunction isAroundEqual$1(a, b) {\n    return Math.abs(a - b) < EPSILON$3;\n}\n\nfunction contain$1(points, x, y) {\n    var w = 0;\n    var p = points[0];\n\n    if (!p) {\n        return false;\n    }\n\n    for (var i = 1; i < points.length; i++) {\n        var p2 = points[i];\n        w += windingLine(p[0], p[1], p2[0], p2[1], x, y);\n        p = p2;\n    }\n\n    // Close polygon\n    var p0 = points[0];\n    if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) {\n        w += windingLine(p[0], p[1], p0[0], p0[1], x, y);\n    }\n\n    return w !== 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/geo/Region\n */\n\n/**\n * @param {string|Region} name\n * @param {Array} geometries\n * @param {Array.<number>} cp\n */\nfunction Region(name, geometries, cp) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.name = name;\n\n    /**\n     * @type {Array.<Array>}\n     * @readOnly\n     */\n    this.geometries = geometries;\n\n    if (!cp) {\n        var rect = this.getBoundingRect();\n        cp = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n    else {\n        cp = [cp[0], cp[1]];\n    }\n    /**\n     * @type {Array.<number>}\n     */\n    this.center = cp;\n}\n\nRegion.prototype = {\n\n    constructor: Region,\n\n    properties: null,\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        var rect = this._rect;\n        if (rect) {\n            return rect;\n        }\n\n        var MAX_NUMBER = Number.MAX_VALUE;\n        var min$$1 = [MAX_NUMBER, MAX_NUMBER];\n        var max$$1 = [-MAX_NUMBER, -MAX_NUMBER];\n        var min2 = [];\n        var max2 = [];\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            // Doesn't consider hole\n            var exterior = geometries[i].exterior;\n            fromPoints(exterior, min2, max2);\n            min(min$$1, min$$1, min2);\n            max(max$$1, max$$1, max2);\n        }\n        // No data\n        if (i === 0) {\n            min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0;\n        }\n\n        return (this._rect = new BoundingRect(\n            min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]\n        ));\n    },\n\n    /**\n     * @param {<Array.<number>} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var rect = this.getBoundingRect();\n        var geometries = this.geometries;\n        if (!rect.contain(coord[0], coord[1])) {\n            return false;\n        }\n        loopGeo: for (var i = 0, len$$1 = geometries.length; i < len$$1; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            if (contain$1(exterior, coord[0], coord[1])) {\n                // Not in the region if point is in the hole.\n                for (var k = 0; k < (interiors ? interiors.length : 0); k++) {\n                    if (contain$1(interiors[k])) {\n                        continue loopGeo;\n                    }\n                }\n                return true;\n            }\n        }\n        return false;\n    },\n\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var aspect = rect.width / rect.height;\n        if (!width) {\n            width = aspect * height;\n        }\n        else if (!height) {\n            height = width / aspect;\n        }\n        var target = new BoundingRect(x, y, width, height);\n        var transform = rect.calculateTransform(target);\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            for (var p = 0; p < exterior.length; p++) {\n                applyTransform(exterior[p], exterior[p], transform);\n            }\n            for (var h = 0; h < (interiors ? interiors.length : 0); h++) {\n                for (var p = 0; p < interiors[h].length; p++) {\n                    applyTransform(interiors[h][p], interiors[h][p], transform);\n                }\n            }\n        }\n        rect = this._rect;\n        rect.copy(target);\n        // Update center\n        this.center = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    },\n\n    cloneShallow: function (name) {\n        name == null && (name = this.name);\n        var newRegion = new Region(name, this.geometries, this.center);\n        newRegion._rect = this._rect;\n        newRegion.transformTo = null; // Simply avoid to be called.\n        return newRegion;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parse and decode geo json\n * @module echarts/coord/geo/parseGeoJson\n */\n\nfunction decode(json) {\n    if (!json.UTF8Encoding) {\n        return json;\n    }\n    var encodeScale = json.UTF8Scale;\n    if (encodeScale == null) {\n        encodeScale = 1024;\n    }\n\n    var features = json.features;\n\n    for (var f = 0; f < features.length; f++) {\n        var feature = features[f];\n        var geometry = feature.geometry;\n        var coordinates = geometry.coordinates;\n        var encodeOffsets = geometry.encodeOffsets;\n\n        for (var c = 0; c < coordinates.length; c++) {\n            var coordinate = coordinates[c];\n\n            if (geometry.type === 'Polygon') {\n                coordinates[c] = decodePolygon(\n                    coordinate,\n                    encodeOffsets[c],\n                    encodeScale\n                );\n            }\n            else if (geometry.type === 'MultiPolygon') {\n                for (var c2 = 0; c2 < coordinate.length; c2++) {\n                    var polygon = coordinate[c2];\n                    coordinate[c2] = decodePolygon(\n                        polygon,\n                        encodeOffsets[c][c2],\n                        encodeScale\n                    );\n                }\n            }\n        }\n    }\n    // Has been decoded\n    json.UTF8Encoding = false;\n    return json;\n}\n\nfunction decodePolygon(coordinate, encodeOffsets, encodeScale) {\n    var result = [];\n    var prevX = encodeOffsets[0];\n    var prevY = encodeOffsets[1];\n\n    for (var i = 0; i < coordinate.length; i += 2) {\n        var x = coordinate.charCodeAt(i) - 64;\n        var y = coordinate.charCodeAt(i + 1) - 64;\n        // ZigZag decoding\n        x = (x >> 1) ^ (-(x & 1));\n        y = (y >> 1) ^ (-(y & 1));\n        // Delta deocding\n        x += prevX;\n        y += prevY;\n\n        prevX = x;\n        prevY = y;\n        // Dequantize\n        result.push([x / encodeScale, y / encodeScale]);\n    }\n\n    return result;\n}\n\n/**\n * @alias module:echarts/coord/geo/parseGeoJson\n * @param {Object} geoJson\n * @return {module:zrender/container/Group}\n */\nvar parseGeoJson$1 = function (geoJson) {\n\n    decode(geoJson);\n\n    return map(filter(geoJson.features, function (featureObj) {\n        // Output of mapshaper may have geometry null\n        return featureObj.geometry\n            && featureObj.properties\n            && featureObj.geometry.coordinates.length > 0;\n    }), function (featureObj) {\n        var properties = featureObj.properties;\n        var geo = featureObj.geometry;\n\n        var coordinates = geo.coordinates;\n\n        var geometries = [];\n        if (geo.type === 'Polygon') {\n            geometries.push({\n                type: 'polygon',\n                // According to the GeoJSON specification.\n                // First must be exterior, and the rest are all interior(holes).\n                exterior: coordinates[0],\n                interiors: coordinates.slice(1)\n            });\n        }\n        if (geo.type === 'MultiPolygon') {\n            each$1(coordinates, function (item) {\n                if (item[0]) {\n                    geometries.push({\n                        type: 'polygon',\n                        exterior: item[0],\n                        interiors: item.slice(1)\n                    });\n                }\n            });\n        }\n\n        var region = new Region(\n            properties.name,\n            geometries,\n            properties.cp\n        );\n        region.properties = properties;\n        return region;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Do not mount those modules on 'src/echarts' for better tree shaking.\n */\n\nvar parseGeoJson = parseGeoJson$1;\n\nvar ecUtil = {};\neach$1(\n    [\n        'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',\n        'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',\n        'extend', 'defaults', 'clone', 'merge'\n    ],\n    function (name) {\n        ecUtil[name] = zrUtil[name];\n    }\n);\nvar graphic$1 = {};\neach$1(\n    [\n        'extendShape', 'extendPath', 'makePath', 'makeImage',\n        'mergePath', 'resizePath', 'createIcon',\n        'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText',\n        'getFont', 'updateProps', 'initProps', 'getTransform',\n        'clipPointsByRect', 'clipRectByRect',\n        'Group',\n        'Image',\n        'Text',\n        'Circle',\n        'Sector',\n        'Ring',\n        'Polygon',\n        'Polyline',\n        'Rect',\n        'Line',\n        'BezierCurve',\n        'Arc',\n        'IncrementalDisplayable',\n        'CompoundPath',\n        'LinearGradient',\n        'RadialGradient',\n        'BoundingRect'\n    ],\n    function (name) {\n        graphic$1[name] = graphic[name];\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz$1(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz$1.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz$1.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz$1;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz$1.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz$1(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar pointsLayout = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$6 = each$1;\nvar curry$1 = curry;\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\nfunction collect(ecModel, api) {\n    var result = {\n        /**\n         * key: makeKey(axis.model)\n         * value: {\n         *      axis,\n         *      coordSys,\n         *      axisPointerModel,\n         *      triggerTooltip,\n         *      involveSeries,\n         *      snap,\n         *      seriesModels,\n         *      seriesDataCount\n         * }\n         */\n        axesInfo: {},\n        seriesInvolved: false,\n        /**\n         * key: makeKey(coordSys.model)\n         * value: Object: key makeKey(axis.model), value: axisInfo\n         */\n        coordSysAxesInfo: {},\n        coordSysMap: {}\n    };\n\n    collectAxesInfo(result, ecModel, api);\n\n    // Check seriesInvolved for performance, in case too many series in some chart.\n    result.seriesInvolved && collectSeriesInfo(result, ecModel);\n\n    return result;\n}\n\nfunction collectAxesInfo(result, ecModel, api) {\n    var globalTooltipModel = ecModel.getComponent('tooltip');\n    var globalAxisPointerModel = ecModel.getComponent('axisPointer');\n    // links can only be set on global.\n    var linksOption = globalAxisPointerModel.get('link', true) || [];\n    var linkGroups = [];\n\n    // Collect axes info.\n    each$6(api.getCoordinateSystems(), function (coordSys) {\n        // Some coordinate system do not support axes, like geo.\n        if (!coordSys.axisPointerEnabled) {\n            return;\n        }\n\n        var coordSysKey = makeKey(coordSys.model);\n        var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};\n        result.coordSysMap[coordSysKey] = coordSys;\n\n        // Set tooltip (like 'cross') is a convienent way to show axisPointer\n        // for user. So we enable seting tooltip on coordSys model.\n        var coordSysModel = coordSys.model;\n        var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);\n\n        each$6(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null));\n\n        // If axis tooltip used, choose tooltip axis for each coordSys.\n        // Notice this case: coordSys is `grid` but not `cartesian2D` here.\n        if (coordSys.getTooltipAxes\n            && globalTooltipModel\n            // If tooltip.showContent is set as false, tooltip will not\n            // show but axisPointer will show as normal.\n            && baseTooltipModel.get('show')\n        ) {\n            // Compatible with previous logic. But series.tooltip.trigger: 'axis'\n            // or series.data[n].tooltip.trigger: 'axis' are not support any more.\n            var triggerAxis = baseTooltipModel.get('trigger') === 'axis';\n            var cross = baseTooltipModel.get('axisPointer.type') === 'cross';\n            var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get('axisPointer.axis'));\n            if (triggerAxis || cross) {\n                each$6(tooltipAxes.baseAxes, curry$1(\n                    saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis\n                ));\n            }\n            if (cross) {\n                each$6(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false));\n            }\n        }\n\n        // fromTooltip: true | false | 'cross'\n        // triggerTooltip: true | false | null\n        function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {\n            var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);\n\n            var axisPointerShow = axisPointerModel.get('show');\n            if (!axisPointerShow || (\n                axisPointerShow === 'auto'\n                && !fromTooltip\n                && !isHandleTrigger(axisPointerModel)\n            )) {\n                return;\n            }\n\n            if (triggerTooltip == null) {\n                triggerTooltip = axisPointerModel.get('triggerTooltip');\n            }\n\n            axisPointerModel = fromTooltip\n                ? makeAxisPointerModel(\n                    axis, baseTooltipModel, globalAxisPointerModel, ecModel,\n                    fromTooltip, triggerTooltip\n                )\n                : axisPointerModel;\n\n            var snap = axisPointerModel.get('snap');\n            var key = makeKey(axis.model);\n            var involveSeries = triggerTooltip || snap || axis.type === 'category';\n\n            // If result.axesInfo[key] exist, override it (tooltip has higher priority).\n            var axisInfo = result.axesInfo[key] = {\n                key: key,\n                axis: axis,\n                coordSys: coordSys,\n                axisPointerModel: axisPointerModel,\n                triggerTooltip: triggerTooltip,\n                involveSeries: involveSeries,\n                snap: snap,\n                useHandle: isHandleTrigger(axisPointerModel),\n                seriesModels: []\n            };\n            axesInfoInCoordSys[key] = axisInfo;\n            result.seriesInvolved |= involveSeries;\n\n            var groupIndex = getLinkGroupIndex(linksOption, axis);\n            if (groupIndex != null) {\n                var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {axesInfo: {}});\n                linkGroup.axesInfo[key] = axisInfo;\n                linkGroup.mapper = linksOption[groupIndex].mapper;\n                axisInfo.linkGroup = linkGroup;\n            }\n        }\n    });\n}\n\nfunction makeAxisPointerModel(\n    axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip\n) {\n    var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');\n    var volatileOption = {};\n\n    each$6(\n        [\n            'type', 'snap', 'lineStyle', 'shadowStyle', 'label',\n            'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'\n        ],\n        function (field) {\n            volatileOption[field] = clone(tooltipAxisPointerModel.get(field));\n        }\n    );\n\n    // category axis do not auto snap, otherwise some tick that do not\n    // has value can not be hovered. value/time/log axis default snap if\n    // triggered from tooltip and trigger tooltip.\n    volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;\n\n    // Compatibel with previous behavior, tooltip axis do not show label by default.\n    // Only these properties can be overrided from tooltip to axisPointer.\n    if (tooltipAxisPointerModel.get('type') === 'cross') {\n        volatileOption.type = 'line';\n    }\n    var labelOption = volatileOption.label || (volatileOption.label = {});\n    // Follow the convention, do not show label when triggered by tooltip by default.\n    labelOption.show == null && (labelOption.show = false);\n\n    if (fromTooltip === 'cross') {\n        // When 'cross', both axes show labels.\n        var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get('label.show');\n        labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;\n        // If triggerTooltip, this is a base axis, which should better not use cross style\n        // (cross style is dashed by default)\n        if (!triggerTooltip) {\n            var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');\n            crossStyle && defaults(labelOption, crossStyle.textStyle);\n        }\n    }\n\n    return axis.model.getModel(\n        'axisPointer',\n        new Model(volatileOption, globalAxisPointerModel, ecModel)\n    );\n}\n\nfunction collectSeriesInfo(result, ecModel) {\n    // Prepare data for axis trigger\n    ecModel.eachSeries(function (seriesModel) {\n\n        // Notice this case: this coordSys is `cartesian2D` but not `grid`.\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesTooltipTrigger = seriesModel.get('tooltip.trigger', true);\n        var seriesTooltipShow = seriesModel.get('tooltip.show', true);\n        if (!coordSys\n            || seriesTooltipTrigger === 'none'\n            || seriesTooltipTrigger === false\n            || seriesTooltipTrigger === 'item'\n            || seriesTooltipShow === false\n            || seriesModel.get('axisPointer.show', true) === false\n        ) {\n            return;\n        }\n\n        each$6(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {\n            var axis = axisInfo.axis;\n            if (coordSys.getAxis(axis.dim) === axis) {\n                axisInfo.seriesModels.push(seriesModel);\n                axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);\n                axisInfo.seriesDataCount += seriesModel.getData().count();\n            }\n        });\n\n    }, this);\n}\n\n/**\n * For example:\n * {\n *     axisPointer: {\n *         links: [{\n *             xAxisIndex: [2, 4],\n *             yAxisIndex: 'all'\n *         }, {\n *             xAxisId: ['a5', 'a7'],\n *             xAxisName: 'xxx'\n *         }]\n *     }\n * }\n */\nfunction getLinkGroupIndex(linksOption, axis) {\n    var axisModel = axis.model;\n    var dim = axis.dim;\n    for (var i = 0; i < linksOption.length; i++) {\n        var linkOption = linksOption[i] || {};\n        if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id)\n            || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex)\n            || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)\n        ) {\n            return i;\n        }\n    }\n}\n\nfunction checkPropInLink(linkPropValue, axisPropValue) {\n    return linkPropValue === 'all'\n        || (isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0)\n        || linkPropValue === axisPropValue;\n}\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(pointsLayout('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar selectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.scatter',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            // PENDING\n            return this.option.large ? 5e3 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            // PENDING\n            return this.option.large ? 1e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10,          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n        // cursor: null,\n\n        // label: {\n            // show: false\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为\n            //           'inside'|'left'|'right'|'top'|'bottom'\n            // 默认使用全局文本样式，详见TEXTSTYLE\n        // },\n        itemStyle: {\n            opacity: 0.8\n            // color: 各异\n        }\n\n        // progressive: null\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\n// TODO Batch by color\n\nvar BOOST_SIZE_THRESHOLD = 4;\n\nvar LargeSymbolPath = extendShape({\n\n    shape: {\n        points: null\n    },\n\n    symbolProxy: null,\n\n    buildPath: function (path, shape) {\n        var points = shape.points;\n        var size = shape.size;\n\n        var symbolProxy = this.symbolProxy;\n        var symbolProxyShape = symbolProxy.shape;\n        var ctx = path.getContext ? path.getContext() : path;\n        var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;\n\n        // Do draw in afterBrush.\n        if (canBoost) {\n            return;\n        }\n\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n\n            symbolProxyShape.x = x - size[0] / 2;\n            symbolProxyShape.y = y - size[1] / 2;\n            symbolProxyShape.width = size[0];\n            symbolProxyShape.height = size[1];\n\n            symbolProxy.buildPath(path, symbolProxyShape, true);\n        }\n    },\n\n    afterBrush: function (ctx) {\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n        var canBoost = size[0] < BOOST_SIZE_THRESHOLD;\n\n        if (!canBoost) {\n            return;\n        }\n\n        this.setTransform(ctx);\n        // PENDING If style or other canvas status changed?\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n            // fillRect is faster than building a rect path and draw.\n            // And it support light globalCompositeOperation.\n            ctx.fillRect(\n                x - size[0] / 2, y - size[1] / 2,\n                size[0], size[1]\n            );\n        }\n\n        this.restoreTransform(ctx);\n    },\n\n    findDataIndex: function (x, y) {\n        // TODO ???\n        // Consider transform\n\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n\n        var w = Math.max(size[0], 4);\n        var h = Math.max(size[1], 4);\n\n        // Not consider transform\n        // Treat each element as a rect\n        // top down traverse\n        for (var idx = points.length / 2 - 1; idx >= 0; idx--) {\n            var i = idx * 2;\n            var x0 = points[i] - w / 2;\n            var y0 = points[i + 1] - h / 2;\n            if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) {\n                return idx;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeSymbolDraw() {\n    this.group = new Group();\n}\n\nvar largeSymbolProto = LargeSymbolDraw.prototype;\n\nlargeSymbolProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeSymbolProto.updateData = function (data) {\n    this.group.removeAll();\n    var symbolEl = new LargeSymbolPath({\n        rectHover: true,\n        cursor: 'default'\n    });\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data);\n    this.group.add(symbolEl);\n\n    this._incremental = null;\n};\n\nlargeSymbolProto.updateLayout = function (data) {\n    if (this._incremental) {\n        return;\n    }\n\n    var points = data.getLayout('symbolPoints');\n    this.group.eachChild(function (child) {\n        if (child.startIndex != null) {\n            var len = (child.endIndex - child.startIndex) * 2;\n            var byteOffset = child.startIndex * 4 * 2;\n            points = new Float32Array(points.buffer, byteOffset, len);\n        }\n        child.setShape('points', points);\n    });\n};\n\nlargeSymbolProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n    // Only use incremental displayables when data amount is larger than 2 million.\n    // PENDING Incremental data?\n    if (data.count() > 2e6) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\nlargeSymbolProto.incrementalUpdate = function (taskParams, data) {\n    var symbolEl;\n    if (this._incremental) {\n        symbolEl = new LargeSymbolPath();\n        this._incremental.addDisplayable(symbolEl, true);\n    }\n    else {\n        symbolEl = new LargeSymbolPath({\n            rectHover: true,\n            cursor: 'default',\n            startIndex: taskParams.start,\n            endIndex: taskParams.end\n        });\n        symbolEl.incremental = true;\n        this.group.add(symbolEl);\n    }\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data, !!this._incremental);\n};\n\nlargeSymbolProto._setCommon = function (symbolEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    // TODO\n    // if (data.hasItemVisual.symbolSize) {\n    //     // TODO typed array?\n    //     symbolEl.setShape('sizes', data.mapArray(\n    //         function (idx) {\n    //             var size = data.getItemVisual(idx, 'symbolSize');\n    //             return (size instanceof Array) ? size : [size, size];\n    //         }\n    //     ));\n    // }\n    // else {\n    var size = data.getVisual('symbolSize');\n    symbolEl.setShape('size', (size instanceof Array) ? size : [size, size]);\n    // }\n\n    // Create symbolProxy to build path for each data\n    symbolEl.symbolProxy = createSymbol(\n        data.getVisual('symbol'), 0, 0, 0, 0\n    );\n    // Use symbolProxy setColor method\n    symbolEl.setColor = symbolEl.symbolProxy.setColor;\n\n    var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD;\n    symbolEl.useStyle(\n        // Draw shadow when doing fillRect is extremely slow.\n        hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color'])\n    );\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        symbolEl.setColor(visualColor);\n    }\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        symbolEl.seriesIndex = hostModel.seriesIndex;\n        symbolEl.on('mousemove', function (e) {\n            symbolEl.dataIndex = null;\n            var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex >= 0) {\n                // Provide dataIndex for tooltip\n                symbolEl.dataIndex = dataIndex + (symbolEl.startIndex || 0);\n            }\n        });\n    }\n};\n\nlargeSymbolProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeSymbolProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'scatter',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n        symbolDraw.updateData(data);\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n\n        symbolDraw.incrementalPrepareUpdate(data);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        // Must mark group dirty and make sure the incremental layer will be cleared\n        // PENDING\n        this.group.dirty();\n\n        if (!this._finished || data.count() > 1e4 || !this._symbolDraw.isPersistent()) {\n            return {\n                update: true\n            };\n        }\n        else {\n            var res = pointsLayout().reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n\n            this._symbolDraw.updateLayout(data);\n        }\n    },\n\n    _updateSymbolDraw: function (data, seriesModel) {\n        var symbolDraw = this._symbolDraw;\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (!symbolDraw || isLargeDraw !== this._isLargeDraw) {\n            symbolDraw && symbolDraw.remove();\n            symbolDraw = this._symbolDraw = isLargeDraw\n                ? new LargeSymbolDraw()\n                : new SymbolDraw();\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(symbolDraw.group);\n\n        return symbolDraw;\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(true);\n        this._symbolDraw = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as zrUtil from 'zrender/src/core/util';\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('scatter', 'circle'));\nregisterLayout(pointsLayout('scatter'));\n\n// echarts.registerProcessor(function (ecModel, api) {\n//     ecModel.eachSeriesByType('scatter', function (seriesModel) {\n//         var data = seriesModel.getData();\n//         var coordSys = seriesModel.coordinateSystem;\n//         if (coordSys.type !== 'geo') {\n//             return;\n//         }\n//         var startPt = coordSys.pointToData([0, 0]);\n//         var endPt = coordSys.pointToData([api.getWidth(), api.getHeight()]);\n\n//         var dims = zrUtil.map(coordSys.dimensions, function (dim) {\n//             return data.mapDimension(dim);\n//         });\n//         var range = {};\n//         range[dims[0]] = [Math.min(startPt[0], endPt[0]), Math.max(startPt[0], endPt[0])];\n//         range[dims[1]] = [Math.min(startPt[1], endPt[1]), Math.max(startPt[1], endPt[1])];\n\n//         data.selectRange(range);\n//     });\n// });\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction IndicatorAxis(dim, scale, radiusExtent) {\n    Axis.call(this, dim, scale, radiusExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'value';\n\n    this.angle = 0;\n\n    /**\n     * Indicator name\n     * @type {string}\n     */\n    this.name = '';\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.model;\n}\n\ninherits(IndicatorAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO clockwise\n\nfunction Radar(radarModel, ecModel, api) {\n\n    this._model = radarModel;\n    /**\n     * Radar dimensions\n     * @type {Array.<string>}\n     */\n    this.dimensions = [];\n\n    this._indicatorAxes = map(radarModel.getIndicatorModels(), function (indicatorModel, idx) {\n        var dim = 'indicator_' + idx;\n        var indicatorAxis = new IndicatorAxis(dim, new IntervalScale());\n        indicatorAxis.name = indicatorModel.get('name');\n        // Inject model and axis\n        indicatorAxis.model = indicatorModel;\n        indicatorModel.axis = indicatorAxis;\n        this.dimensions.push(dim);\n        return indicatorAxis;\n    }, this);\n\n    this.resize(radarModel, api);\n\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.cx;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.cy;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.r;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.r0;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.startAngle;\n}\n\nRadar.prototype.getIndicatorAxes = function () {\n    return this._indicatorAxes;\n};\n\nRadar.prototype.dataToPoint = function (value, indicatorIndex) {\n    var indicatorAxis = this._indicatorAxes[indicatorIndex];\n\n    return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex);\n};\n\nRadar.prototype.coordToPoint = function (coord, indicatorIndex) {\n    var indicatorAxis = this._indicatorAxes[indicatorIndex];\n    var angle = indicatorAxis.angle;\n    var x = this.cx + coord * Math.cos(angle);\n    var y = this.cy - coord * Math.sin(angle);\n    return [x, y];\n};\n\nRadar.prototype.pointToData = function (pt) {\n    var dx = pt[0] - this.cx;\n    var dy = pt[1] - this.cy;\n    var radius = Math.sqrt(dx * dx + dy * dy);\n    dx /= radius;\n    dy /= radius;\n\n    var radian = Math.atan2(-dy, dx);\n\n    // Find the closest angle\n    // FIXME index can calculated directly\n    var minRadianDiff = Infinity;\n    var closestAxis;\n    var closestAxisIdx = -1;\n    for (var i = 0; i < this._indicatorAxes.length; i++) {\n        var indicatorAxis = this._indicatorAxes[i];\n        var diff = Math.abs(radian - indicatorAxis.angle);\n        if (diff < minRadianDiff) {\n            closestAxis = indicatorAxis;\n            closestAxisIdx = i;\n            minRadianDiff = diff;\n        }\n    }\n\n    return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))];\n};\n\nRadar.prototype.resize = function (radarModel, api) {\n    var center = radarModel.get('center');\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    var viewSize = Math.min(viewWidth, viewHeight) / 2;\n    this.cx = parsePercent$1(center[0], viewWidth);\n    this.cy = parsePercent$1(center[1], viewHeight);\n\n    this.startAngle = radarModel.get('startAngle') * Math.PI / 180;\n\n    // radius may be single value like `20`, `'80%'`, or array like `[10, '80%']`\n    var radius = radarModel.get('radius');\n    if (typeof radius === 'string' || typeof radius === 'number') {\n        radius = [0, radius];\n    }\n    this.r0 = parsePercent$1(radius[0], viewSize);\n    this.r = parsePercent$1(radius[1], viewSize);\n\n    each$1(this._indicatorAxes, function (indicatorAxis, idx) {\n        indicatorAxis.setExtent(this.r0, this.r);\n        var angle = (this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length);\n        // Normalize to [-PI, PI]\n        angle = Math.atan2(Math.sin(angle), Math.cos(angle));\n        indicatorAxis.angle = angle;\n    }, this);\n};\n\nRadar.prototype.update = function (ecModel, api) {\n    var indicatorAxes = this._indicatorAxes;\n    var radarModel = this._model;\n    each$1(indicatorAxes, function (indicatorAxis) {\n        indicatorAxis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeriesByType('radar', function (radarSeries, idx) {\n        if (radarSeries.get('coordinateSystem') !== 'radar'\n            || ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel\n        ) {\n            return;\n        }\n        var data = radarSeries.getData();\n        each$1(indicatorAxes, function (indicatorAxis) {\n            indicatorAxis.scale.unionExtentFromData(data, data.mapDimension(indicatorAxis.dim));\n        });\n    }, this);\n\n    var splitNumber = radarModel.get('splitNumber');\n\n    function increaseInterval(interval) {\n        var exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10));\n        // Increase interval\n        var f = interval / exp10;\n        if (f === 2) {\n            f = 5;\n        }\n        else { // f is 2 or 5\n            f *= 2;\n        }\n        return f * exp10;\n    }\n    // Force all the axis fixing the maxSplitNumber.\n    each$1(indicatorAxes, function (indicatorAxis, idx) {\n        var rawExtent = getScaleExtent(indicatorAxis.scale, indicatorAxis.model);\n        niceScaleExtent(indicatorAxis.scale, indicatorAxis.model);\n\n        var axisModel = indicatorAxis.model;\n        var scale = indicatorAxis.scale;\n        var fixedMin = axisModel.getMin();\n        var fixedMax = axisModel.getMax();\n        var interval = scale.getInterval();\n\n        if (fixedMin != null && fixedMax != null) {\n            // User set min, max, divide to get new interval\n            scale.setExtent(+fixedMin, +fixedMax);\n            scale.setInterval(\n                (fixedMax - fixedMin) / splitNumber\n            );\n        }\n        else if (fixedMin != null) {\n            var max;\n            // User set min, expand extent on the other side\n            do {\n                max = fixedMin + interval * splitNumber;\n                scale.setExtent(+fixedMin, max);\n                // Interval must been set after extent\n                // FIXME\n                scale.setInterval(interval);\n\n                interval = increaseInterval(interval);\n            } while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1]));\n        }\n        else if (fixedMax != null) {\n            var min;\n            // User set min, expand extent on the other side\n            do {\n                min = fixedMax - interval * splitNumber;\n                scale.setExtent(min, +fixedMax);\n                scale.setInterval(interval);\n                interval = increaseInterval(interval);\n            } while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0]));\n        }\n        else {\n            var nicedSplitNumber = scale.getTicks().length - 1;\n            if (nicedSplitNumber > splitNumber) {\n                interval = increaseInterval(interval);\n            }\n            // PENDING\n            var center = Math.round((rawExtent[0] + rawExtent[1]) / 2 / interval) * interval;\n            var halfSplitNumber = Math.round(splitNumber / 2);\n            scale.setExtent(\n                round$2(center - halfSplitNumber * interval),\n                round$2(center + (splitNumber - halfSplitNumber) * interval)\n            );\n            scale.setInterval(interval);\n        }\n    });\n};\n\n/**\n * Radar dimensions is based on the data\n * @type {Array}\n */\nRadar.dimensions = [];\n\nRadar.create = function (ecModel, api) {\n    var radarList = [];\n    ecModel.eachComponent('radar', function (radarModel) {\n        var radar = new Radar(radarModel, ecModel, api);\n        radarList.push(radar);\n        radarModel.coordinateSystem = radar;\n    });\n    ecModel.eachSeriesByType('radar', function (radarSeries) {\n        if (radarSeries.get('coordinateSystem') === 'radar') {\n            // Inject coordinate system\n            radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0];\n        }\n    });\n    return radarList;\n};\n\nCoordinateSystemManager.register('radar', Radar);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar valueAxisDefault = axisDefault.valueAxis;\n\nfunction defaultsShow(opt, show) {\n    return defaults({\n        show: show\n    }, opt);\n}\n\nvar RadarModel = extendComponentModel({\n\n    type: 'radar',\n\n    optionUpdated: function () {\n        var boundaryGap = this.get('boundaryGap');\n        var splitNumber = this.get('splitNumber');\n        var scale = this.get('scale');\n        var axisLine = this.get('axisLine');\n        var axisTick = this.get('axisTick');\n        var axisLabel = this.get('axisLabel');\n        var nameTextStyle = this.get('name');\n        var showName = this.get('name.show');\n        var nameFormatter = this.get('name.formatter');\n        var nameGap = this.get('nameGap');\n        var triggerEvent = this.get('triggerEvent');\n\n        var indicatorModels = map(this.get('indicator') || [], function (indicatorOpt) {\n            // PENDING\n            if (indicatorOpt.max != null && indicatorOpt.max > 0 && !indicatorOpt.min) {\n                indicatorOpt.min = 0;\n            }\n            else if (indicatorOpt.min != null && indicatorOpt.min < 0 && !indicatorOpt.max) {\n                indicatorOpt.max = 0;\n            }\n            var iNameTextStyle = nameTextStyle;\n            if (indicatorOpt.color != null) {\n                iNameTextStyle = defaults({color: indicatorOpt.color}, nameTextStyle);\n            }\n            // Use same configuration\n            indicatorOpt = merge(clone(indicatorOpt), {\n                boundaryGap: boundaryGap,\n                splitNumber: splitNumber,\n                scale: scale,\n                axisLine: axisLine,\n                axisTick: axisTick,\n                axisLabel: axisLabel,\n                // Competitable with 2 and use text\n                name: indicatorOpt.text,\n                nameLocation: 'end',\n                nameGap: nameGap,\n                // min: 0,\n                nameTextStyle: iNameTextStyle,\n                triggerEvent: triggerEvent\n            }, false);\n            if (!showName) {\n                indicatorOpt.name = '';\n            }\n            if (typeof nameFormatter === 'string') {\n                var indName = indicatorOpt.name;\n                indicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : '');\n            }\n            else if (typeof nameFormatter === 'function') {\n                indicatorOpt.name = nameFormatter(\n                    indicatorOpt.name, indicatorOpt\n                );\n            }\n            var model = extend(\n                new Model(indicatorOpt, null, this.ecModel),\n                axisModelCommonMixin\n            );\n\n            // For triggerEvent.\n            model.mainType = 'radar';\n            model.componentIndex = this.componentIndex;\n\n            return model;\n        }, this);\n\n        this.getIndicatorModels = function () {\n            return indicatorModels;\n        };\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        center: ['50%', '50%'],\n\n        radius: '75%',\n\n        startAngle: 90,\n\n        name: {\n            show: true\n            // formatter: null\n            // textStyle: {}\n        },\n\n        boundaryGap: [0, 0],\n\n        splitNumber: 5,\n\n        nameGap: 15,\n\n        scale: false,\n\n        // Polygon or circle\n        shape: 'polygon',\n\n        axisLine: merge(\n            {\n                lineStyle: {\n                    color: '#bbb'\n                }\n            },\n            valueAxisDefault.axisLine\n        ),\n        axisLabel: defaultsShow(valueAxisDefault.axisLabel, false),\n        axisTick: defaultsShow(valueAxisDefault.axisTick, false),\n        splitLine: defaultsShow(valueAxisDefault.splitLine, true),\n        splitArea: defaultsShow(valueAxisDefault.splitArea, true),\n\n        // {text, min, max}\n        indicator: []\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs$1 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\n\nextendComponentView({\n\n    type: 'radar',\n\n    render: function (radarModel, ecModel, api) {\n        var group = this.group;\n        group.removeAll();\n\n        this._buildAxes(radarModel);\n        this._buildSplitLineAndArea(radarModel);\n    },\n\n    _buildAxes: function (radarModel) {\n        var radar = radarModel.coordinateSystem;\n        var indicatorAxes = radar.getIndicatorAxes();\n        var axisBuilders = map(indicatorAxes, function (indicatorAxis) {\n            var axisBuilder = new AxisBuilder(indicatorAxis.model, {\n                position: [radar.cx, radar.cy],\n                rotation: indicatorAxis.angle,\n                labelDirection: -1,\n                tickDirection: -1,\n                nameDirection: 1\n            });\n            return axisBuilder;\n        });\n\n        each$1(axisBuilders, function (axisBuilder) {\n            each$1(axisBuilderAttrs$1, axisBuilder.add, axisBuilder);\n            this.group.add(axisBuilder.getGroup());\n        }, this);\n    },\n\n    _buildSplitLineAndArea: function (radarModel) {\n        var radar = radarModel.coordinateSystem;\n        var indicatorAxes = radar.getIndicatorAxes();\n        if (!indicatorAxes.length) {\n            return;\n        }\n        var shape = radarModel.get('shape');\n        var splitLineModel = radarModel.getModel('splitLine');\n        var splitAreaModel = radarModel.getModel('splitArea');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n\n        var showSplitLine = splitLineModel.get('show');\n        var showSplitArea = splitAreaModel.get('show');\n        var splitLineColors = lineStyleModel.get('color');\n        var splitAreaColors = areaStyleModel.get('color');\n\n        splitLineColors = isArray(splitLineColors) ? splitLineColors : [splitLineColors];\n        splitAreaColors = isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors];\n\n        var splitLines = [];\n        var splitAreas = [];\n\n        function getColorIndex(areaOrLine, areaOrLineColorList, idx) {\n            var colorIndex = idx % areaOrLineColorList.length;\n            areaOrLine[colorIndex] = areaOrLine[colorIndex] || [];\n            return colorIndex;\n        }\n\n        if (shape === 'circle') {\n            var ticksRadius = indicatorAxes[0].getTicksCoords();\n            var cx = radar.cx;\n            var cy = radar.cy;\n            for (var i = 0; i < ticksRadius.length; i++) {\n                if (showSplitLine) {\n                    var colorIndex = getColorIndex(splitLines, splitLineColors, i);\n                    splitLines[colorIndex].push(new Circle({\n                        shape: {\n                            cx: cx,\n                            cy: cy,\n                            r: ticksRadius[i].coord\n                        }\n                    }));\n                }\n                if (showSplitArea && i < ticksRadius.length - 1) {\n                    var colorIndex = getColorIndex(splitAreas, splitAreaColors, i);\n                    splitAreas[colorIndex].push(new Ring({\n                        shape: {\n                            cx: cx,\n                            cy: cy,\n                            r0: ticksRadius[i].coord,\n                            r: ticksRadius[i + 1].coord\n                        }\n                    }));\n                }\n            }\n        }\n        // Polyyon\n        else {\n            var realSplitNumber;\n            var axesTicksPoints = map(indicatorAxes, function (indicatorAxis, idx) {\n                var ticksCoords = indicatorAxis.getTicksCoords();\n                realSplitNumber = realSplitNumber == null\n                    ? ticksCoords.length - 1\n                    : Math.min(ticksCoords.length - 1, realSplitNumber);\n                return map(ticksCoords, function (tickCoord) {\n                    return radar.coordToPoint(tickCoord.coord, idx);\n                });\n            });\n\n            var prevPoints = [];\n            for (var i = 0; i <= realSplitNumber; i++) {\n                var points = [];\n                for (var j = 0; j < indicatorAxes.length; j++) {\n                    points.push(axesTicksPoints[j][i]);\n                }\n                // Close\n                if (points[0]) {\n                    points.push(points[0].slice());\n                }\n                else {\n                    if (__DEV__) {\n                        console.error('Can\\'t draw value axis ' + i);\n                    }\n                }\n\n                if (showSplitLine) {\n                    var colorIndex = getColorIndex(splitLines, splitLineColors, i);\n                    splitLines[colorIndex].push(new Polyline({\n                        shape: {\n                            points: points\n                        }\n                    }));\n                }\n                if (showSplitArea && prevPoints) {\n                    var colorIndex = getColorIndex(splitAreas, splitAreaColors, i - 1);\n                    splitAreas[colorIndex].push(new Polygon({\n                        shape: {\n                            points: points.concat(prevPoints)\n                        }\n                    }));\n                }\n                prevPoints = points.slice().reverse();\n            }\n        }\n\n        var lineStyle = lineStyleModel.getLineStyle();\n        var areaStyle = areaStyleModel.getAreaStyle();\n        // Add splitArea before splitLine\n        each$1(splitAreas, function (splitAreas, idx) {\n            this.group.add(mergePath(\n                splitAreas, {\n                    style: defaults({\n                        stroke: 'none',\n                        fill: splitAreaColors[idx % splitAreaColors.length]\n                    }, areaStyle),\n                    silent: true\n                }\n            ));\n        }, this);\n\n        each$1(splitLines, function (splitLines, idx) {\n            this.group.add(mergePath(\n                splitLines, {\n                    style: defaults({\n                        fill: 'none',\n                        stroke: splitLineColors[idx % splitLineColors.length]\n                    }, lineStyle),\n                    silent: true\n                }\n            ));\n        }, this);\n\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar RadarSeries = SeriesModel.extend({\n\n    type: 'series.radar',\n\n    dependencies: ['radar'],\n\n\n    // Overwrite\n    init: function (option) {\n        RadarSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, {\n            generateCoord: 'indicator_',\n            generateCoordCount: Infinity\n        });\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var coordSys = this.coordinateSystem;\n        var indicatorAxes = coordSys.getIndicatorAxes();\n        var name = this.getData().getName(dataIndex);\n        return encodeHTML(name === '' ? this.name : name) + '<br/>'\n            + map(indicatorAxes, function (axis, idx) {\n                var val = data.get(data.mapDimension(axis.dim), dataIndex);\n                return encodeHTML(axis.name + ' : ' + val);\n            }).join('<br />');\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'radar',\n        legendHoverLink: true,\n        radarIndex: 0,\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        label: {\n            position: 'top'\n        },\n        // areaStyle: {\n        // },\n        // itemStyle: {}\n        symbol: 'emptyCircle',\n        symbolSize: 4\n        // symbolRotate: null\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction normalizeSymbolSize(symbolSize) {\n    if (!isArray(symbolSize)) {\n        symbolSize = [+symbolSize, +symbolSize];\n    }\n    return symbolSize;\n}\n\nextendChartView({\n\n    type: 'radar',\n\n    render: function (seriesModel, ecModel, api) {\n        var polar = seriesModel.coordinateSystem;\n        var group = this.group;\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        function createSymbol$$1(data, idx) {\n            var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n            var color = data.getItemVisual(idx, 'color');\n            if (symbolType === 'none') {\n                return;\n            }\n            var symbolSize = normalizeSymbolSize(\n                data.getItemVisual(idx, 'symbolSize')\n            );\n            var symbolPath = createSymbol(\n                symbolType, -1, -1, 2, 2, color\n            );\n            symbolPath.attr({\n                style: {\n                    strokeNoScale: true\n                },\n                z2: 100,\n                scale: [symbolSize[0] / 2, symbolSize[1] / 2]\n            });\n            return symbolPath;\n        }\n\n        function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) {\n            // Simply rerender all\n            symbolGroup.removeAll();\n            for (var i = 0; i < newPoints.length - 1; i++) {\n                var symbolPath = createSymbol$$1(data, idx);\n                if (symbolPath) {\n                    symbolPath.__dimIdx = i;\n                    if (oldPoints[i]) {\n                        symbolPath.attr('position', oldPoints[i]);\n                        graphic[isInit ? 'initProps' : 'updateProps'](\n                            symbolPath, {\n                                position: newPoints[i]\n                            }, seriesModel, idx\n                        );\n                    }\n                    else {\n                        symbolPath.attr('position', newPoints[i]);\n                    }\n                    symbolGroup.add(symbolPath);\n                }\n            }\n        }\n\n        function getInitialPoints(points) {\n            return map(points, function (pt) {\n                return [polar.cx, polar.cy];\n            });\n        }\n        data.diff(oldData)\n            .add(function (idx) {\n                var points = data.getItemLayout(idx);\n                if (!points) {\n                    return;\n                }\n                var polygon = new Polygon();\n                var polyline = new Polyline();\n                var target = {\n                    shape: {\n                        points: points\n                    }\n                };\n                polygon.shape.points = getInitialPoints(points);\n                polyline.shape.points = getInitialPoints(points);\n                initProps(polygon, target, seriesModel, idx);\n                initProps(polyline, target, seriesModel, idx);\n\n                var itemGroup = new Group();\n                var symbolGroup = new Group();\n                itemGroup.add(polyline);\n                itemGroup.add(polygon);\n                itemGroup.add(symbolGroup);\n\n                updateSymbols(\n                    polyline.shape.points, points, symbolGroup, data, idx, true\n                );\n\n                data.setItemGraphicEl(idx, itemGroup);\n            })\n            .update(function (newIdx, oldIdx) {\n                var itemGroup = oldData.getItemGraphicEl(oldIdx);\n                var polyline = itemGroup.childAt(0);\n                var polygon = itemGroup.childAt(1);\n                var symbolGroup = itemGroup.childAt(2);\n                var target = {\n                    shape: {\n                        points: data.getItemLayout(newIdx)\n                    }\n                };\n                if (!target.shape.points) {\n                    return;\n                }\n                updateSymbols(\n                    polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false\n                );\n\n                updateProps(polyline, target, seriesModel);\n                updateProps(polygon, target, seriesModel);\n\n                data.setItemGraphicEl(newIdx, itemGroup);\n            })\n            .remove(function (idx) {\n                group.remove(oldData.getItemGraphicEl(idx));\n            })\n            .execute();\n\n        data.eachItemGraphicEl(function (itemGroup, idx) {\n            var itemModel = data.getItemModel(idx);\n            var polyline = itemGroup.childAt(0);\n            var polygon = itemGroup.childAt(1);\n            var symbolGroup = itemGroup.childAt(2);\n            var color = data.getItemVisual(idx, 'color');\n\n            group.add(itemGroup);\n\n            polyline.useStyle(\n                defaults(\n                    itemModel.getModel('lineStyle').getLineStyle(),\n                    {\n                        fill: 'none',\n                        stroke: color\n                    }\n                )\n            );\n            polyline.hoverStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n            var areaStyleModel = itemModel.getModel('areaStyle');\n            var hoverAreaStyleModel = itemModel.getModel('emphasis.areaStyle');\n            var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();\n            var hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty();\n\n            hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore;\n            polygon.ignore = polygonIgnore;\n\n            polygon.useStyle(\n                defaults(\n                    areaStyleModel.getAreaStyle(),\n                    {\n                        fill: color,\n                        opacity: 0.7\n                    }\n                )\n            );\n            polygon.hoverStyle = hoverAreaStyleModel.getAreaStyle();\n\n            var itemStyle = itemModel.getModel('itemStyle').getItemStyle(['color']);\n            var itemHoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            symbolGroup.eachChild(function (symbolPath) {\n                symbolPath.setStyle(itemStyle);\n                symbolPath.hoverStyle = clone(itemHoverStyle);\n\n                setLabelStyle(\n                    symbolPath.style, symbolPath.hoverStyle, labelModel, labelHoverModel,\n                    {\n                        labelFetcher: data.hostModel,\n                        labelDataIndex: idx,\n                        labelDimIndex: symbolPath.__dimIdx,\n                        defaultText: data.get(data.dimensions[symbolPath.__dimIdx], idx),\n                        autoColor: color,\n                        isRectText: true\n                    }\n                );\n            });\n\n            function onEmphasis() {\n                polygon.attr('ignore', hoverPolygonIgnore);\n            }\n\n            function onNormal() {\n                polygon.attr('ignore', polygonIgnore);\n            }\n\n            itemGroup.off('mouseover').off('mouseout').off('normal').off('emphasis');\n            itemGroup.on('emphasis', onEmphasis)\n                .on('mouseover', onEmphasis)\n                .on('normal', onNormal)\n                .on('mouseout', onNormal);\n\n            setHoverStyle(itemGroup);\n        });\n\n        this._data = data;\n    },\n\n    remove: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar radarLayout = function (ecModel) {\n    ecModel.eachSeriesByType('radar', function (seriesModel) {\n        var data = seriesModel.getData();\n        var points = [];\n        var coordSys = seriesModel.coordinateSystem;\n        if (!coordSys) {\n            return;\n        }\n\n        function pointsConverter(val, idx) {\n            points[idx] = points[idx] || [];\n            points[idx][i] = coordSys.dataToPoint(val, i);\n        }\n        var axes = coordSys.getIndicatorAxes();\n        for (var i = 0; i < axes.length; i++) {\n            data.each(data.mapDimension(axes[i].dim), pointsConverter);\n        }\n\n        data.each(function (idx) {\n            // Close polygon\n            points[idx][0] && points[idx].push(points[idx][0].slice());\n            data.setItemLayout(idx, points[idx]);\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Backward compat for radar chart in 2\nvar backwardCompat$1 = function (option) {\n    var polarOptArr = option.polar;\n    if (polarOptArr) {\n        if (!isArray(polarOptArr)) {\n            polarOptArr = [polarOptArr];\n        }\n        var polarNotRadar = [];\n        each$1(polarOptArr, function (polarOpt, idx) {\n            if (polarOpt.indicator) {\n                if (polarOpt.type && !polarOpt.shape) {\n                    polarOpt.shape = polarOpt.type;\n                }\n                option.radar = option.radar || [];\n                if (!isArray(option.radar)) {\n                    option.radar = [option.radar];\n                }\n                option.radar.push(polarOpt);\n            }\n            else {\n                polarNotRadar.push(polarOpt);\n            }\n        });\n        option.polar = polarNotRadar;\n    }\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'radar' && seriesOpt.polarIndex) {\n            seriesOpt.radarIndex = seriesOpt.polarIndex;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Must use radar component\nregisterVisual(dataColor('radar'));\nregisterVisual(visualSymbol('radar', 'circle'));\nregisterLayout(radarLayout);\nregisterProcessor(dataFilter('radar'));\nregisterPreprocessor(backwardCompat$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Fix for 南海诸岛\n\nvar geoCoord = [126, 25];\n\nvar points$1 = [\n    [[0, 3.5], [7, 11.2], [15, 11.9], [30, 7], [42, 0.7], [52, 0.7],\n        [56, 7.7], [59, 0.7], [64, 0.7], [64, 0], [5, 0], [0, 3.5]],\n    [[13, 16.1], [19, 14.7], [16, 21.7], [11, 23.1], [13, 16.1]],\n    [[12, 32.2], [14, 38.5], [15, 38.5], [13, 32.2], [12, 32.2]],\n    [[16, 47.6], [12, 53.2], [13, 53.2], [18, 47.6], [16, 47.6]],\n    [[6, 64.4], [8, 70], [9, 70], [8, 64.4], [6, 64.4]],\n    [[23, 82.6], [29, 79.8], [30, 79.8], [25, 82.6], [23, 82.6]],\n    [[37, 70.7], [43, 62.3], [44, 62.3], [39, 70.7], [37, 70.7]],\n    [[48, 51.1], [51, 45.5], [53, 45.5], [50, 51.1], [48, 51.1]],\n    [[51, 35], [51, 28.7], [53, 28.7], [53, 35], [51, 35]],\n    [[52, 22.4], [55, 17.5], [56, 17.5], [53, 22.4], [52, 22.4]],\n    [[58, 12.6], [62, 7], [63, 7], [60, 12.6], [58, 12.6]],\n    [[0, 3.5], [0, 93.1], [64, 93.1], [64, 0], [63, 0], [63, 92.4],\n        [1, 92.4], [1, 3.5], [0, 3.5]]\n];\n\nfor (var i$1 = 0; i$1 < points$1.length; i$1++) {\n    for (var k = 0; k < points$1[i$1].length; k++) {\n        points$1[i$1][k][0] /= 10.5;\n        points$1[i$1][k][1] /= -10.5 / 0.75;\n\n        points$1[i$1][k][0] += geoCoord[0];\n        points$1[i$1][k][1] += geoCoord[1];\n    }\n}\n\nvar fixNanhai = function (mapType, regions) {\n    if (mapType === 'china') {\n        regions.push(new Region(\n            '南海诸岛',\n            map(points$1, function (exterior) {\n                return {\n                    type: 'polygon',\n                    exterior: exterior\n                };\n            }), geoCoord\n        ));\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordsOffsetMap = {\n    '南海诸岛': [32, 80],\n    // 全国\n    '广东': [0, -10],\n    '香港': [10, 5],\n    '澳门': [-10, 10],\n    //'北京': [-10, 0],\n    '天津': [5, 5]\n};\n\nvar fixTextCoord = function (mapType, region) {\n    if (mapType === 'china') {\n        var coordFix = coordsOffsetMap[region.name];\n        if (coordFix) {\n            var cp = region.center;\n            cp[0] += coordFix[0] / 10.5;\n            cp[1] += -coordFix[1] / (10.5 / 0.75);\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar geoCoordMap = {\n    'Russia': [100, 60],\n    'United States': [-99, 38],\n    'United States of America': [-99, 38]\n};\n\nvar fixGeoCoord = function (mapType, region) {\n    if (mapType === 'world') {\n        var geoCoord = geoCoordMap[region.name];\n        if (geoCoord) {\n            var cp = region.center;\n            cp[0] = geoCoord[0];\n            cp[1] = geoCoord[1];\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Fix for 钓鱼岛\n\n// var Region = require('../Region');\n// var zrUtil = require('zrender/src/core/util');\n\n// var geoCoord = [126, 25];\n\nvar points$2 = [\n    [\n        [123.45165252685547, 25.73527164402261],\n        [123.49731445312499, 25.73527164402261],\n        [123.49731445312499, 25.750734064600884],\n        [123.45165252685547, 25.750734064600884],\n        [123.45165252685547, 25.73527164402261]\n    ]\n];\n\nvar fixDiaoyuIsland = function (mapType, region) {\n    if (mapType === 'china' && region.name === '台湾') {\n        region.geometries.push({\n            type: 'polygon',\n            exterior: points$2[0]\n        });\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Built-in GEO fixer.\nvar inner$7 = makeInner();\n\nvar geoJSONLoader = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} mapRecord {specialAreas, geoJSON}\n     * @return {Object} {regions, boundingRect}\n     */\n    load: function (mapName, mapRecord) {\n\n        var parsed = inner$7(mapRecord).parsed;\n\n        if (parsed) {\n            return parsed;\n        }\n\n        var specialAreas = mapRecord.specialAreas || {};\n        var geoJSON = mapRecord.geoJSON;\n        var regions;\n\n        // https://jsperf.com/try-catch-performance-overhead\n        try {\n            regions = geoJSON ? parseGeoJson$1(geoJSON) : [];\n        }\n        catch (e) {\n            throw new Error('Invalid geoJson format\\n' + e.message);\n        }\n\n        each$1(regions, function (region) {\n            var regionName = region.name;\n\n            fixTextCoord(mapName, region);\n            fixGeoCoord(mapName, region);\n            fixDiaoyuIsland(mapName, region);\n\n            // Some area like Alaska in USA map needs to be tansformed\n            // to look better\n            var specialArea = specialAreas[regionName];\n            if (specialArea) {\n                region.transformTo(\n                    specialArea.left, specialArea.top, specialArea.width, specialArea.height\n                );\n            }\n        });\n\n        fixNanhai(mapName, regions);\n\n        return (inner$7(mapRecord).parsed = {\n            regions: regions,\n            boundingRect: getBoundingRect$1(regions)\n        });\n    }\n};\n\nfunction getBoundingRect$1(regions) {\n    var rect;\n    for (var i = 0; i < regions.length; i++) {\n        var regionRect = regions[i].getBoundingRect();\n        rect = rect || regionRect.clone();\n        rect.union(regionRect);\n    }\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$8 = makeInner();\n\nvar geoSVGLoader = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} mapRecord {specialAreas, geoJSON}\n     * @return {Object} {root, boundingRect}\n     */\n    load: function (mapName, mapRecord) {\n        var originRoot = inner$8(mapRecord).originRoot;\n        if (originRoot) {\n            return {\n                root: originRoot,\n                boundingRect: inner$8(mapRecord).boundingRect\n            };\n        }\n\n        var graphic = buildGraphic(mapRecord);\n\n        inner$8(mapRecord).originRoot = graphic.root;\n        inner$8(mapRecord).boundingRect = graphic.boundingRect;\n\n        return graphic;\n    },\n\n    makeGraphic: function (mapName, mapRecord, hostKey) {\n        // For performance consideration (in large SVG), graphic only maked\n        // when necessary and reuse them according to hostKey.\n        var field = inner$8(mapRecord);\n        var rootMap = field.rootMap || (field.rootMap = createHashMap());\n\n        var root = rootMap.get(hostKey);\n        if (root) {\n            return root;\n        }\n\n        var originRoot = field.originRoot;\n        var boundingRect = field.boundingRect;\n\n        // For performance, if originRoot is not used by a view,\n        // assign it to a view, but not reproduce graphic elements.\n        if (!field.originRootHostKey) {\n            field.originRootHostKey = hostKey;\n            root = originRoot;\n        }\n        else {\n            root = buildGraphic(mapRecord, boundingRect).root;\n        }\n\n        return rootMap.set(hostKey, root);\n    },\n\n    removeGraphic: function (mapName, mapRecord, hostKey) {\n        var field = inner$8(mapRecord);\n        var rootMap = field.rootMap;\n        rootMap && rootMap.removeKey(hostKey);\n        if (hostKey === field.originRootHostKey) {\n            field.originRootHostKey = null;\n        }\n    }\n};\n\nfunction buildGraphic(mapRecord, boundingRect) {\n    var svgXML = mapRecord.svgXML;\n    var result;\n    var root;\n\n    try {\n        result = svgXML && parseSVG(svgXML, {\n            ignoreViewBox: true,\n            ignoreRootClip: true\n        }) || {};\n        root = result.root;\n        assert$1(root != null);\n    }\n    catch (e) {\n        throw new Error('Invalid svg format\\n' + e.message);\n    }\n\n    var svgWidth = result.width;\n    var svgHeight = result.height;\n    var viewBoxRect = result.viewBoxRect;\n\n    if (!boundingRect) {\n        boundingRect = (svgWidth == null || svgHeight == null)\n            // If svg width / height not specified, calculate\n            // bounding rect as the width / height\n            ? root.getBoundingRect()\n            : new BoundingRect(0, 0, 0, 0);\n\n        if (svgWidth != null) {\n            boundingRect.width = svgWidth;\n        }\n        if (svgHeight != null) {\n            boundingRect.height = svgHeight;\n        }\n    }\n\n    if (viewBoxRect) {\n        var viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect.width, boundingRect.height);\n        var elRoot = root;\n        root = new Group();\n        root.add(elRoot);\n        elRoot.scale = viewBoxTransform.scale;\n        elRoot.position = viewBoxTransform.position;\n    }\n\n    root.setClipPath(new Rect({\n        shape: boundingRect.plain()\n    }));\n\n    return {\n        root: root,\n        boundingRect: boundingRect\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar loaders = {\n    geoJSON: geoJSONLoader,\n    svg: geoSVGLoader\n};\n\nvar geoSourceManager = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} nameMap\n     * @return {Object} source {regions, regionsMap, nameCoordMap, boundingRect}\n     */\n    load: function (mapName, nameMap) {\n        var regions = [];\n        var regionsMap = createHashMap();\n        var nameCoordMap = createHashMap();\n        var boundingRect;\n        var mapRecords = retrieveMap(mapName);\n\n        each$1(mapRecords, function (record) {\n            var singleSource = loaders[record.type].load(mapName, record);\n\n            each$1(singleSource.regions, function (region) {\n                var regionName = region.name;\n\n                // Try use the alias in geoNameMap\n                if (nameMap && nameMap.hasOwnProperty(regionName)) {\n                    region = region.cloneShallow(regionName = nameMap[regionName]);\n                }\n\n                regions.push(region);\n                regionsMap.set(regionName, region);\n                nameCoordMap.set(regionName, region.center);\n            });\n\n            var rect = singleSource.boundingRect;\n            if (rect) {\n                boundingRect\n                    ? boundingRect.union(rect)\n                    : (boundingRect = rect.clone());\n            }\n        });\n\n        return {\n            regions: regions,\n            regionsMap: regionsMap,\n            nameCoordMap: nameCoordMap,\n            // FIXME Always return new ?\n            boundingRect: boundingRect || new BoundingRect(0, 0, 0, 0)\n        };\n    },\n\n    /**\n     * @param {string} mapName\n     * @param {string} hostKey For cache.\n     * @return {Array.<module:zrender/Element>} Roots.\n     */\n    makeGraphic: makeInvoker('makeGraphic'),\n\n    /**\n     * @param {string} mapName\n     * @param {string} hostKey For cache.\n     */\n    removeGraphic: makeInvoker('removeGraphic')\n};\n\nfunction makeInvoker(methodName) {\n    return function (mapName, hostKey) {\n        var mapRecords = retrieveMap(mapName);\n        var results = [];\n\n        each$1(mapRecords, function (record) {\n            var method = loaders[record.type][methodName];\n            method && results.push(method(mapName, record, hostKey));\n        });\n\n        return results;\n    };\n}\n\nfunction mapNotExistsError(mapName) {\n    if (__DEV__) {\n        console.error(\n            'Map ' + mapName + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html'\n        );\n    }\n}\n\nfunction retrieveMap(mapName) {\n    var mapRecords = mapDataStorage.retrieveMap(mapName) || [];\n\n    if (__DEV__) {\n        if (!mapRecords.length) {\n            mapNotExistsError(mapName);\n        }\n    }\n\n    return mapRecords;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MapSeries = SeriesModel.extend({\n\n    type: 'series.map',\n\n    dependencies: ['geo'],\n\n    layoutMode: 'box',\n\n    /**\n     * Only first map series of same mapType will drawMap\n     * @type {boolean}\n     */\n    needsDrawMap: false,\n\n    /**\n     * Group of all map series with same mapType\n     * @type {boolean}\n     */\n    seriesGroup: [],\n\n    getInitialData: function (option) {\n        var data = createListSimply(this, ['value']);\n        var valueDim = data.mapDimension('value');\n        var dataNameMap = createHashMap();\n        var selectTargetList = [];\n        var toAppendNames = [];\n\n        for (var i = 0, len = data.count(); i < len; i++) {\n            var name = data.getName(i);\n            dataNameMap.set(name, true);\n            selectTargetList.push({\n                name: name,\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n\n        var geoSource = geoSourceManager.load(this.getMapType(), this.option.nameMap);\n        each$1(geoSource.regions, function (region) {\n            var name = region.name;\n            if (!dataNameMap.get(name)) {\n                selectTargetList.push({name: name});\n                toAppendNames.push(name);\n            }\n        });\n\n        this.updateSelectedMap(selectTargetList);\n\n        // Complete data with missing regions. The consequent processes (like visual\n        // map and render) can not be performed without a \"full data\". For example,\n        // find `dataIndex` by name.\n        data.appendValues([], toAppendNames);\n\n        return data;\n    },\n\n    /**\n     * If no host geo model, return null, which means using a\n     * inner exclusive geo model.\n     */\n    getHostGeoModel: function () {\n        var geoIndex = this.option.geoIndex;\n        return geoIndex != null\n            ? this.dependentModels.geo[geoIndex]\n            : null;\n    },\n\n    getMapType: function () {\n        return (this.getHostGeoModel() || this).option.map;\n    },\n\n    // _fillOption: function (option, mapName) {\n        // Shallow clone\n        // option = zrUtil.extend({}, option);\n\n        // option.data = geoCreator.getFilledRegions(option.data, mapName, option.nameMap);\n\n        // return option;\n    // },\n\n    getRawValue: function (dataIndex) {\n        // Use value stored in data instead because it is calculated from multiple series\n        // FIXME Provide all value of multiple series ?\n        var data = this.getData();\n        return data.get(data.mapDimension('value'), dataIndex);\n    },\n\n    /**\n     * Get model of region\n     * @param  {string} name\n     * @return {module:echarts/model/Model}\n     */\n    getRegionModel: function (regionName) {\n        var data = this.getData();\n        return data.getItemModel(data.indexOfName(regionName));\n    },\n\n    /**\n     * Map tooltip formatter\n     *\n     * @param {number} dataIndex\n     */\n    formatTooltip: function (dataIndex) {\n        // FIXME orignalData and data is a bit confusing\n        var data = this.getData();\n        var formattedValue = addCommas(this.getRawValue(dataIndex));\n        var name = data.getName(dataIndex);\n\n        var seriesGroup = this.seriesGroup;\n        var seriesNames = [];\n        for (var i = 0; i < seriesGroup.length; i++) {\n            var otherIndex = seriesGroup[i].originalData.indexOfName(name);\n            var valueDim = data.mapDimension('value');\n            if (!isNaN(seriesGroup[i].originalData.get(valueDim, otherIndex))) {\n                seriesNames.push(\n                    encodeHTML(seriesGroup[i].name)\n                );\n            }\n        }\n\n        return seriesNames.join(', ') + '<br />'\n            + encodeHTML(name + ' : ' + formattedValue);\n    },\n\n    /**\n     * @implement\n     */\n    getTooltipPosition: function (dataIndex) {\n        if (dataIndex != null) {\n            var name = this.getData().getName(dataIndex);\n            var geo = this.coordinateSystem;\n            var region = geo.getRegion(name);\n\n            return region && geo.dataToPoint(region.center);\n        }\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 2,\n\n        coordinateSystem: 'geo',\n\n        // map should be explicitly specified since ec3.\n        map: '',\n\n        // If `geoIndex` is not specified, a exclusive geo will be\n        // created. Otherwise use the specified geo component, and\n        // `map` and `mapType` are ignored.\n        // geoIndex: 0,\n\n        // 'center' | 'left' | 'right' | 'x%' | {number}\n        left: 'center',\n        // 'center' | 'top' | 'bottom' | 'x%' | {number}\n        top: 'center',\n        // right\n        // bottom\n        // width:\n        // height\n\n        // Aspect is width / height. Inited to be geoJson bbox aspect\n        // This parameter is used for scale this aspect\n        aspectScale: 0.75,\n\n        ///// Layout with center and size\n        // If you wan't to put map in a fixed size box with right aspect ratio\n        // This two properties may more conveninet\n        // layoutCenter: [50%, 50%]\n        // layoutSize: 100\n\n\n        // 数值合并方式，默认加和，可选为：\n        // 'sum' | 'average' | 'max' | 'min'\n        // mapValueCalculation: 'sum',\n        // 地图数值计算结果小数精度\n        // mapValuePrecision: 0,\n\n\n        // 显示图例颜色标识（系列标识的小圆点），图例开启时有效\n        showLegendSymbol: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        dataRangeHoverLink: true,\n        // 是否开启缩放及漫游模式\n        // roam: false,\n\n        // Define left-top, right-bottom coords to control view\n        // For example, [ [180, 90], [-180, -90] ],\n        // higher priority than center and zoom\n        boundingCoords: null,\n\n        // Default on center of map\n        center: null,\n\n        zoom: 1,\n\n        scaleLimit: null,\n\n        label: {\n            show: false,\n            color: '#000'\n        },\n        // scaleLimit: null,\n        itemStyle: {\n            borderWidth: 0.5,\n            borderColor: '#444',\n            areaColor: '#eee'\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                color: 'rgb(100,0,0)'\n            },\n            itemStyle: {\n                areaColor: 'rgba(255,215,0,0.8)'\n            }\n        }\n    }\n\n});\n\nmixin(MapSeries, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ATTR = '\\0_ec_interaction_mutex';\n\nfunction take(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    store[resourceKey] = userKey;\n}\n\nfunction release(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    var uKey = store[resourceKey];\n\n    if (uKey === userKey) {\n        store[resourceKey] = null;\n    }\n}\n\nfunction isTaken(zr, resourceKey) {\n    return !!getStore(zr)[resourceKey];\n}\n\nfunction getStore(zr) {\n    return zr[ATTR] || (zr[ATTR] = {});\n}\n\n/**\n * payload: {\n *     type: 'takeGlobalCursor',\n *     key: 'dataZoomSelect', or 'brush', or ...,\n *         If no userKey, release global cursor.\n * }\n */\nregisterAction(\n    {type: 'takeGlobalCursor', event: 'globalCursorTaken', update: 'update'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @alias module:echarts/component/helper/RoamController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction RoamController(zr) {\n\n    /**\n     * @type {Function}\n     */\n    this.pointerChecker;\n\n    /**\n     * @type {module:zrender}\n     */\n    this._zr = zr;\n\n    /**\n     * @type {Object}\n     */\n    this._opt = {};\n\n    // Avoid two roamController bind the same handler\n    var bind$$1 = bind;\n    var mousedownHandler = bind$$1(mousedown, this);\n    var mousemoveHandler = bind$$1(mousemove, this);\n    var mouseupHandler = bind$$1(mouseup, this);\n    var mousewheelHandler = bind$$1(mousewheel, this);\n    var pinchHandler = bind$$1(pinch, this);\n\n    Eventful.call(this);\n\n    /**\n     * @param {Function} pointerChecker\n     *                   input: x, y\n     *                   output: boolean\n     */\n    this.setPointerChecker = function (pointerChecker) {\n        this.pointerChecker = pointerChecker;\n    };\n\n    /**\n     * Notice: only enable needed types. For example, if 'zoom'\n     * is not needed, 'zoom' should not be enabled, otherwise\n     * default mousewheel behaviour (scroll page) will be disabled.\n     *\n     * @param  {boolean|string} [controlType=true] Specify the control type,\n     *                          which can be null/undefined or true/false\n     *                          or 'pan/move' or 'zoom'/'scale'\n     * @param {Object} [opt]\n     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.\n     */\n    this.enable = function (controlType, opt) {\n\n        // Disable previous first\n        this.disable();\n\n        this._opt = defaults(clone(opt) || {}, {\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            // By default, wheel do not trigger move.\n            moveOnMouseWheel: false,\n            preventDefaultMouseMove: true\n        });\n\n        if (controlType == null) {\n            controlType = true;\n        }\n\n        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {\n            zr.on('mousedown', mousedownHandler);\n            zr.on('mousemove', mousemoveHandler);\n            zr.on('mouseup', mouseupHandler);\n        }\n        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {\n            zr.on('mousewheel', mousewheelHandler);\n            zr.on('pinch', pinchHandler);\n        }\n    };\n\n    this.disable = function () {\n        zr.off('mousedown', mousedownHandler);\n        zr.off('mousemove', mousemoveHandler);\n        zr.off('mouseup', mouseupHandler);\n        zr.off('mousewheel', mousewheelHandler);\n        zr.off('pinch', pinchHandler);\n    };\n\n    this.dispose = this.disable;\n\n    this.isDragging = function () {\n        return this._dragging;\n    };\n\n    this.isPinching = function () {\n        return this._pinching;\n    };\n}\n\nmixin(RoamController, Eventful);\n\n\nfunction mousedown(e) {\n    if (isMiddleOrRightButtonOnMouseUpDown(e)\n        || (e.target && e.target.draggable)\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    // Only check on mosedown, but not mousemove.\n    // Mouse can be out of target when mouse moving.\n    if (this.pointerChecker && this.pointerChecker(e, x, y)) {\n        this._x = x;\n        this._y = y;\n        this._dragging = true;\n    }\n}\n\nfunction mousemove(e) {\n    if (!this._dragging\n        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)\n        || e.gestureEvent === 'pinch'\n        || isTaken(this._zr, 'globalPan')\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    var oldX = this._x;\n    var oldY = this._y;\n\n    var dx = x - oldX;\n    var dy = y - oldY;\n\n    this._x = x;\n    this._y = y;\n\n    this._opt.preventDefaultMouseMove && stop(e.event);\n\n    trigger(this, 'pan', 'moveOnMouseMove', e, {\n        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y\n    });\n}\n\nfunction mouseup(e) {\n    if (!isMiddleOrRightButtonOnMouseUpDown(e)) {\n        this._dragging = false;\n    }\n}\n\nfunction mousewheel(e) {\n    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);\n    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);\n    var wheelDelta = e.wheelDelta;\n    var absWheelDeltaDelta = Math.abs(wheelDelta);\n    var originX = e.offsetX;\n    var originY = e.offsetY;\n\n    // wheelDelta maybe -0 in chrome mac.\n    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {\n        return;\n    }\n\n    // If both `shouldZoom` and `shouldMove` is true, trigger\n    // their event both, and the final behavior is determined\n    // by event listener themselves.\n\n    if (shouldZoom) {\n        // Convenience:\n        // Mac and VM Windows on Mac: scroll up: zoom out.\n        // Windows: scroll up: zoom in.\n\n        // FIXME: Should do more test in different environment.\n        // wheelDelta is too complicated in difference nvironment\n        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),\n        // although it has been normallized by zrender.\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;\n        var scale = wheelDelta > 0 ? factor : 1 / factor;\n        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {\n            scale: scale, originX: originX, originY: originY\n        });\n    }\n\n    if (shouldMove) {\n        // FIXME: Should do more test in different environment.\n        var absDelta = Math.abs(wheelDelta);\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);\n        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {\n            scrollDelta: scrollDelta, originX: originX, originY: originY\n        });\n    }\n}\n\nfunction pinch(e) {\n    if (isTaken(this._zr, 'globalPan')) {\n        return;\n    }\n    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;\n    checkPointerAndTrigger(this, 'zoom', null, e, {\n        scale: scale, originX: e.pinchX, originY: e.pinchY\n    });\n}\n\nfunction checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    if (controller.pointerChecker\n        && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)\n    ) {\n        // When mouse is out of roamController rect,\n        // default befavoius should not be be disabled, otherwise\n        // page sliding is disabled, contrary to expectation.\n        stop(e.event);\n\n        trigger(controller, eventName, behaviorToCheck, e, contollerEvent);\n    }\n}\n\nfunction trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    // Also provide behavior checker for event listener, for some case that\n    // multiple components share one listener.\n    contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);\n    controller.trigger(eventName, contollerEvent);\n}\n\n// settings: {\n//     zoomOnMouseWheel\n//     moveOnMouseMove\n//     moveOnMouseWheel\n// }\n// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\nfunction isAvailableBehavior(behaviorToCheck, e, settings) {\n    var setting = settings[behaviorToCheck];\n    return !behaviorToCheck || (\n        setting && (!isString(setting) || e.event[setting + 'Key'])\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * For geo and graph.\n *\n * @param {Object} controllerHost\n * @param {module:zrender/Element} controllerHost.target\n */\nfunction updateViewOnPan(controllerHost, dx, dy) {\n    var target = controllerHost.target;\n    var pos = target.position;\n    pos[0] += dx;\n    pos[1] += dy;\n    target.dirty();\n}\n\n/**\n * For geo and graph.\n *\n * @param {Object} controllerHost\n * @param {module:zrender/Element} controllerHost.target\n * @param {number} controllerHost.zoom\n * @param {number} controllerHost.zoomLimit like: {min: 1, max: 2}\n */\nfunction updateViewOnZoom(controllerHost, zoomDelta, zoomX, zoomY) {\n    var target = controllerHost.target;\n    var zoomLimit = controllerHost.zoomLimit;\n    var pos = target.position;\n    var scale = target.scale;\n\n    var newZoom = controllerHost.zoom = controllerHost.zoom || 1;\n    newZoom *= zoomDelta;\n    if (zoomLimit) {\n        var zoomMin = zoomLimit.min || 0;\n        var zoomMax = zoomLimit.max || Infinity;\n        newZoom = Math.max(\n            Math.min(zoomMax, newZoom),\n            zoomMin\n        );\n    }\n    var zoomScale = newZoom / controllerHost.zoom;\n    controllerHost.zoom = newZoom;\n    // Keep the mouse center when scaling\n    pos[0] -= (zoomX - pos[0]) * (zoomScale - 1);\n    pos[1] -= (zoomY - pos[1]) * (zoomScale - 1);\n    scale[0] *= zoomScale;\n    scale[1] *= zoomScale;\n\n    target.dirty();\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar IRRELEVANT_EXCLUDES = {'axisPointer': 1, 'tooltip': 1, 'brush': 1};\n\n/**\n * Avoid that: mouse click on a elements that is over geo or graph,\n * but roam is triggered.\n */\nfunction onIrrelevantElement(e, api, targetCoordSysModel) {\n    var model = api.getComponentByElement(e.topTarget);\n    // If model is axisModel, it works only if it is injected with coordinateSystem.\n    var coordSys = model && model.coordinateSystem;\n    return model\n        && model !== targetCoordSysModel\n        && !IRRELEVANT_EXCLUDES[model.mainType]\n        && (coordSys && coordSys.model !== targetCoordSysModel);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getFixedItemStyle(model, scale) {\n    var itemStyle = model.getItemStyle();\n    var areaColor = model.get('areaColor');\n\n    // If user want the color not to be changed when hover,\n    // they should both set areaColor and color to be null.\n    if (areaColor != null) {\n        itemStyle.fill = areaColor;\n    }\n\n    return itemStyle;\n}\n\nfunction updateMapSelectHandler(mapDraw, mapOrGeoModel, regionsGroup, api, fromView) {\n    regionsGroup.off('click');\n    regionsGroup.off('mousedown');\n\n    if (mapOrGeoModel.get('selectedMode')) {\n\n        regionsGroup.on('mousedown', function () {\n            mapDraw._mouseDownFlag = true;\n        });\n\n        regionsGroup.on('click', function (e) {\n            if (!mapDraw._mouseDownFlag) {\n                return;\n            }\n            mapDraw._mouseDownFlag = false;\n\n            var el = e.target;\n            while (!el.__regions) {\n                el = el.parent;\n            }\n            if (!el) {\n                return;\n            }\n\n            var action = {\n                type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect',\n                batch: map(el.__regions, function (region) {\n                    return {\n                        name: region.name,\n                        from: fromView.uid\n                    };\n                })\n            };\n            action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id;\n\n            api.dispatchAction(action);\n\n            updateMapSelected(mapOrGeoModel, regionsGroup);\n        });\n    }\n}\n\nfunction updateMapSelected(mapOrGeoModel, regionsGroup) {\n    // FIXME\n    regionsGroup.eachChild(function (otherRegionEl) {\n        each$1(otherRegionEl.__regions, function (region) {\n            otherRegionEl.trigger(mapOrGeoModel.isSelected(region.name) ? 'emphasis' : 'normal');\n        });\n    });\n}\n\n/**\n * @alias module:echarts/component/helper/MapDraw\n * @param {module:echarts/ExtensionAPI} api\n * @param {boolean} updateGroup\n */\nfunction MapDraw(api, updateGroup) {\n\n    var group = new Group();\n\n    /**\n     * @type {string}\n     * @private\n     */\n    this.uid = getUID('ec_map_draw');\n\n    /**\n     * @type {module:echarts/component/helper/RoamController}\n     * @private\n     */\n    this._controller = new RoamController(api.getZr());\n\n    /**\n     * @type {Object} {target, zoom, zoomLimit}\n     * @private\n     */\n    this._controllerHost = {target: updateGroup ? group : null};\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = group;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._updateGroup = updateGroup;\n\n    /**\n     * This flag is used to make sure that only one among\n     * `pan`, `zoom`, `click` can occurs, otherwise 'selected'\n     * action may be triggered when `pan`, which is unexpected.\n     * @type {booelan}\n     */\n    this._mouseDownFlag;\n\n    /**\n     * @type {string}\n     */\n    this._mapName;\n\n    /**\n     * @type {boolean}\n     */\n    this._initialized;\n\n    /**\n     * @type {module:zrender/container/Group}\n     */\n    group.add(this._regionsGroup = new Group());\n\n    /**\n     * @type {module:zrender/container/Group}\n     */\n    group.add(this._backgroundGroup = new Group());\n}\n\nMapDraw.prototype = {\n\n    constructor: MapDraw,\n\n    draw: function (mapOrGeoModel, ecModel, api, fromView, payload) {\n\n        var isGeo = mapOrGeoModel.mainType === 'geo';\n\n        // Map series has data. GEO model that controlled by map series\n        // will be assigned with map data. Other GEO model has no data.\n        var data = mapOrGeoModel.getData && mapOrGeoModel.getData();\n        isGeo && ecModel.eachComponent({mainType: 'series', subType: 'map'}, function (mapSeries) {\n            if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) {\n                data = mapSeries.getData();\n            }\n        });\n\n        var geo = mapOrGeoModel.coordinateSystem;\n\n        this._updateBackground(geo);\n\n        var regionsGroup = this._regionsGroup;\n        var group = this.group;\n\n        var scale = geo.scale;\n        var transform = {\n            position: geo.position,\n            scale: scale\n        };\n\n        // No animation when first draw or in action\n        if (!regionsGroup.childAt(0) || payload) {\n            group.attr(transform);\n        }\n        else {\n            updateProps(group, transform, mapOrGeoModel);\n        }\n\n        regionsGroup.removeAll();\n\n        var itemStyleAccessPath = ['itemStyle'];\n        var hoverItemStyleAccessPath = ['emphasis', 'itemStyle'];\n        var labelAccessPath = ['label'];\n        var hoverLabelAccessPath = ['emphasis', 'label'];\n        var nameMap = createHashMap();\n\n        each$1(geo.regions, function (region) {\n\n            // Consider in GeoJson properties.name may be duplicated, for example,\n            // there is multiple region named \"United Kindom\" or \"France\" (so many\n            // colonies). And it is not appropriate to merge them in geo, which\n            // will make them share the same label and bring trouble in label\n            // location calculation.\n            var regionGroup = nameMap.get(region.name)\n                || nameMap.set(region.name, new Group());\n\n            var compoundPath = new CompoundPath({\n                shape: {\n                    paths: []\n                }\n            });\n            regionGroup.add(compoundPath);\n\n            var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;\n\n            var itemStyleModel = regionModel.getModel(itemStyleAccessPath);\n            var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);\n            var itemStyle = getFixedItemStyle(itemStyleModel, scale);\n            var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale);\n\n            var labelModel = regionModel.getModel(labelAccessPath);\n            var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath);\n\n            var dataIdx;\n            // Use the itemStyle in data if has data\n            if (data) {\n                dataIdx = data.indexOfName(region.name);\n                // Only visual color of each item will be used. It can be encoded by dataRange\n                // But visual color of series is used in symbol drawing\n                //\n                // Visual color for each series is for the symbol draw\n                var visualColor = data.getItemVisual(dataIdx, 'color', true);\n                if (visualColor) {\n                    itemStyle.fill = visualColor;\n                }\n            }\n\n            each$1(region.geometries, function (geometry) {\n                if (geometry.type !== 'polygon') {\n                    return;\n                }\n                compoundPath.shape.paths.push(new Polygon({\n                    shape: {\n                        points: geometry.exterior\n                    }\n                }));\n\n                for (var i = 0; i < (geometry.interiors ? geometry.interiors.length : 0); i++) {\n                    compoundPath.shape.paths.push(new Polygon({\n                        shape: {\n                            points: geometry.interiors[i]\n                        }\n                    }));\n                }\n            });\n\n            compoundPath.setStyle(itemStyle);\n            compoundPath.style.strokeNoScale = true;\n            compoundPath.culling = true;\n            // Label\n            var showLabel = labelModel.get('show');\n            var hoverShowLabel = hoverLabelModel.get('show');\n\n            var isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx));\n            var itemLayout = data && data.getItemLayout(dataIdx);\n            // In the following cases label will be drawn\n            // 1. In map series and data value is NaN\n            // 2. In geo component\n            // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout\n            if (\n                (isGeo || isDataNaN && (showLabel || hoverShowLabel))\n                || (itemLayout && itemLayout.showLabel)\n            ) {\n                var query = !isGeo ? dataIdx : region.name;\n                var labelFetcher;\n\n                // Consider dataIdx not found.\n                if (!data || dataIdx >= 0) {\n                    labelFetcher = mapOrGeoModel;\n                }\n\n                var textEl = new Text({\n                    position: region.center.slice(),\n                    // FIXME\n                    // label rotation is not support yet in geo or regions of series-map\n                    // that has no data. The rotation will be effected by this `scale`.\n                    // So needed to change to RectText?\n                    scale: [1 / scale[0], 1 / scale[1]],\n                    z2: 10,\n                    silent: true\n                });\n\n                setLabelStyle(\n                    textEl.style, textEl.hoverStyle = {}, labelModel, hoverLabelModel,\n                    {\n                        labelFetcher: labelFetcher,\n                        labelDataIndex: query,\n                        defaultText: region.name,\n                        useInsideStyle: false\n                    },\n                    {\n                        textAlign: 'center',\n                        textVerticalAlign: 'middle'\n                    }\n                );\n\n                regionGroup.add(textEl);\n            }\n\n            // setItemGraphicEl, setHoverStyle after all polygons and labels\n            // are added to the rigionGroup\n            if (data) {\n                data.setItemGraphicEl(dataIdx, regionGroup);\n            }\n            else {\n                var regionModel = mapOrGeoModel.getRegionModel(region.name);\n                // Package custom mouse event for geo component\n                compoundPath.eventData = {\n                    componentType: 'geo',\n                    componentIndex: mapOrGeoModel.componentIndex,\n                    geoIndex: mapOrGeoModel.componentIndex,\n                    name: region.name,\n                    region: (regionModel && regionModel.option) || {}\n                };\n            }\n\n            var groupRegions = regionGroup.__regions || (regionGroup.__regions = []);\n            groupRegions.push(region);\n\n            setHoverStyle(\n                regionGroup,\n                hoverItemStyle,\n                {hoverSilentOnTouch: !!mapOrGeoModel.get('selectedMode')}\n            );\n\n            regionsGroup.add(regionGroup);\n        });\n\n        this._updateController(mapOrGeoModel, ecModel, api);\n\n        updateMapSelectHandler(this, mapOrGeoModel, regionsGroup, api, fromView);\n\n        updateMapSelected(mapOrGeoModel, regionsGroup);\n    },\n\n    remove: function () {\n        this._regionsGroup.removeAll();\n        this._backgroundGroup.removeAll();\n        this._controller.dispose();\n        this._mapName && geoSourceManager.removeGraphic(this._mapName, this.uid);\n        this._mapName = null;\n        this._controllerHost = {};\n    },\n\n    _updateBackground: function (geo) {\n        var mapName = geo.map;\n\n        if (this._mapName !== mapName) {\n            each$1(geoSourceManager.makeGraphic(mapName, this.uid), function (root) {\n                this._backgroundGroup.add(root);\n            }, this);\n        }\n\n        this._mapName = mapName;\n    },\n\n    _updateController: function (mapOrGeoModel, ecModel, api) {\n        var geo = mapOrGeoModel.coordinateSystem;\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n\n        controllerHost.zoomLimit = mapOrGeoModel.get('scaleLimit');\n        controllerHost.zoom = geo.getZoom();\n\n        // roamType is will be set default true if it is null\n        controller.enable(mapOrGeoModel.get('roam') || false);\n        var mainType = mapOrGeoModel.mainType;\n\n        function makeActionBase() {\n            var action = {\n                type: 'geoRoam',\n                componentType: mainType\n            };\n            action[mainType + 'Id'] = mapOrGeoModel.id;\n            return action;\n        }\n\n        controller.off('pan').on('pan', function (e) {\n            this._mouseDownFlag = false;\n\n            updateViewOnPan(controllerHost, e.dx, e.dy);\n\n            api.dispatchAction(extend(makeActionBase(), {\n                dx: e.dx,\n                dy: e.dy\n            }));\n        }, this);\n\n        controller.off('zoom').on('zoom', function (e) {\n            this._mouseDownFlag = false;\n\n            updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n\n            api.dispatchAction(extend(makeActionBase(), {\n                zoom: e.scale,\n                originX: e.originX,\n                originY: e.originY\n            }));\n\n            if (this._updateGroup) {\n                var scale = this.group.scale;\n                this._regionsGroup.traverse(function (el) {\n                    if (el.type === 'text') {\n                        el.attr('scale', [1 / scale[0], 1 / scale[1]]);\n                    }\n                });\n            }\n        }, this);\n\n        controller.setPointerChecker(function (e, x, y) {\n            return geo.getViewRectAfterRoam().contain(x, y)\n                && !onIrrelevantElement(e, api, mapOrGeoModel);\n        });\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar HIGH_DOWN_PROP = '__seriesMapHighDown';\nvar RECORD_VERSION_PROP = '__seriesMapCallKey';\n\nextendChartView({\n\n    type: 'map',\n\n    render: function (mapModel, ecModel, api, payload) {\n        // Not render if it is an toggleSelect action from self\n        if (payload && payload.type === 'mapToggleSelect'\n            && payload.from === this.uid\n        ) {\n            return;\n        }\n\n        var group = this.group;\n        group.removeAll();\n\n        if (mapModel.getHostGeoModel()) {\n            return;\n        }\n\n        // Not update map if it is an roam action from self\n        if (!(payload && payload.type === 'geoRoam'\n                && payload.componentType === 'series'\n                && payload.seriesId === mapModel.id\n            )\n        ) {\n            if (mapModel.needsDrawMap) {\n                var mapDraw = this._mapDraw || new MapDraw(api, true);\n                group.add(mapDraw.group);\n\n                mapDraw.draw(mapModel, ecModel, api, this, payload);\n\n                this._mapDraw = mapDraw;\n            }\n            else {\n                // Remove drawed map\n                this._mapDraw && this._mapDraw.remove();\n                this._mapDraw = null;\n            }\n        }\n        else {\n            var mapDraw = this._mapDraw;\n            mapDraw && group.add(mapDraw.group);\n        }\n\n        mapModel.get('showLegendSymbol') && ecModel.getComponent('legend')\n            && this._renderSymbols(mapModel, ecModel, api);\n    },\n\n    remove: function () {\n        this._mapDraw && this._mapDraw.remove();\n        this._mapDraw = null;\n        this.group.removeAll();\n    },\n\n    dispose: function () {\n        this._mapDraw && this._mapDraw.remove();\n        this._mapDraw = null;\n    },\n\n    _renderSymbols: function (mapModel, ecModel, api) {\n        var originalData = mapModel.originalData;\n        var group = this.group;\n\n        originalData.each(originalData.mapDimension('value'), function (value, originalDataIndex) {\n            if (isNaN(value)) {\n                return;\n            }\n\n            var layout = originalData.getItemLayout(originalDataIndex);\n\n            if (!layout || !layout.point) {\n                // Not exists in map\n                return;\n            }\n\n            var point = layout.point;\n            var offset = layout.offset;\n\n            var circle = new Circle({\n                style: {\n                    // Because the special of map draw.\n                    // Which needs statistic of multiple series and draw on one map.\n                    // And each series also need a symbol with legend color\n                    //\n                    // Layout and visual are put one the different data\n                    fill: mapModel.getData().getVisual('color')\n                },\n                shape: {\n                    cx: point[0] + offset * 9,\n                    cy: point[1],\n                    r: 3\n                },\n                silent: true,\n                // Do not overlap the first series, on which labels are displayed.\n                z2: 8 + (!offset ? Z2_EMPHASIS_LIFT + 1 : 0)\n            });\n\n            // Only the series that has the first value on the same region is in charge of rendering the label.\n            // But consider the case:\n            // series: [\n            //     {id: 'X', type: 'map', map: 'm', {data: [{name: 'A', value: 11}, {name: 'B', {value: 22}]},\n            //     {id: 'Y', type: 'map', map: 'm', {data: [{name: 'A', value: 21}, {name: 'C', {value: 33}]}\n            // ]\n            // The offset `0` of item `A` is at series `X`, but of item `C` is at series `Y`.\n            // For backward compatibility, we follow the rule that render label `A` by the\n            // settings on series `X` but render label `C` by the settings on series `Y`.\n            if (!offset) {\n\n                var fullData = mapModel.mainSeries.getData();\n                var name = originalData.getName(originalDataIndex);\n\n                var fullIndex = fullData.indexOfName(name);\n\n                var itemModel = originalData.getItemModel(originalDataIndex);\n                var labelModel = itemModel.getModel('label');\n                var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n                var regionGroup = fullData.getItemGraphicEl(fullIndex);\n\n                // `getFormattedLabel` needs to use `getData` inside. Here\n                // `mapModel.getData()` is shallow cloned from `mainSeries.getData()`.\n                // FIXME\n                // If this is not the `mainSeries`, the item model (like label formatter)\n                // set on original data item will never get. But it has been working\n                // like that from the begining, and this scenario is rarely encountered.\n                // So it won't be fixed until have to.\n                var normalText = retrieve2(\n                    mapModel.getFormattedLabel(fullIndex, 'normal'),\n                    name\n                );\n                var emphasisText = retrieve2(\n                    mapModel.getFormattedLabel(fullIndex, 'emphasis'),\n                    normalText\n                );\n\n                var highDownRecord = regionGroup[HIGH_DOWN_PROP];\n                var recordVersion = Math.random();\n\n                // Prevent from register listeners duplicatedly when roaming.\n                if (!highDownRecord) {\n                    highDownRecord = regionGroup[HIGH_DOWN_PROP] = {};\n                    var onEmphasis = curry(onRegionHighDown, true);\n                    var onNormal = curry(onRegionHighDown, false);\n                    regionGroup.on('mouseover', onEmphasis)\n                        .on('mouseout', onNormal)\n                        .on('emphasis', onEmphasis)\n                        .on('normal', onNormal);\n                }\n\n                // Prevent removed regions effect current grapics.\n                regionGroup[RECORD_VERSION_PROP] = recordVersion;\n                extend(highDownRecord, {\n                    recordVersion: recordVersion,\n                    circle: circle,\n                    labelModel: labelModel,\n                    hoverLabelModel: hoverLabelModel,\n                    emphasisText: emphasisText,\n                    normalText: normalText\n                });\n\n                // FIXME\n                // Consider set option when emphasis.\n                enterRegionHighDown(highDownRecord, false);\n            }\n\n            group.add(circle);\n        });\n    }\n});\n\nfunction onRegionHighDown(toHighOrDown) {\n    var highDownRecord = this[HIGH_DOWN_PROP];\n    if (highDownRecord && highDownRecord.recordVersion === this[RECORD_VERSION_PROP]) {\n        enterRegionHighDown(highDownRecord, toHighOrDown);\n    }\n}\n\nfunction enterRegionHighDown(highDownRecord, toHighOrDown) {\n    var circle = highDownRecord.circle;\n    var labelModel = highDownRecord.labelModel;\n    var hoverLabelModel = highDownRecord.hoverLabelModel;\n    var emphasisText = highDownRecord.emphasisText;\n    var normalText = highDownRecord.normalText;\n\n    if (toHighOrDown) {\n        circle.style.extendFrom(\n            setTextStyle({}, hoverLabelModel, {\n                text: hoverLabelModel.get('show') ? emphasisText : null\n            }, {isRectText: true, useInsideStyle: false}, true)\n        );\n        // Make label upper than others if overlaps.\n        circle.__mapOriginalZ2 = circle.z2;\n        circle.z2 += Z2_EMPHASIS_LIFT;\n    }\n    else {\n        setTextStyle(circle.style, labelModel, {\n            text: labelModel.get('show') ? normalText : null,\n            textPosition: labelModel.getShallow('position') || 'bottom'\n        }, {isRectText: true, useInsideStyle: false});\n        // Trigger normalize style like padding.\n        circle.dirty(false);\n\n        if (circle.__mapOriginalZ2 != null) {\n            circle.z2 = circle.__mapOriginalZ2;\n            circle.__mapOriginalZ2 = null;\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/coord/View} view\n * @param {Object} payload\n * @param {Object} [zoomLimit]\n */\nfunction updateCenterAndZoom(\n    view, payload, zoomLimit\n) {\n    var previousZoom = view.getZoom();\n    var center = view.getCenter();\n    var zoom = payload.zoom;\n\n    var point = view.dataToPoint(center);\n\n    if (payload.dx != null && payload.dy != null) {\n        point[0] -= payload.dx;\n        point[1] -= payload.dy;\n\n        var center = view.pointToData(point);\n        view.setCenter(center);\n    }\n    if (zoom != null) {\n        if (zoomLimit) {\n            var zoomMin = zoomLimit.min || 0;\n            var zoomMax = zoomLimit.max || Infinity;\n            zoom = Math.max(\n                Math.min(previousZoom * zoom, zoomMax),\n                zoomMin\n            ) / previousZoom;\n        }\n\n        // Zoom on given point(originX, originY)\n        view.scale[0] *= zoom;\n        view.scale[1] *= zoom;\n        var position = view.position;\n        var fixX = (payload.originX - position[0]) * (zoom - 1);\n        var fixY = (payload.originY - position[1]) * (zoom - 1);\n\n        position[0] -= fixX;\n        position[1] -= fixY;\n\n        view.updateTransform();\n        // Get the new center\n        var center = view.pointToData(point);\n        view.setCenter(center);\n        view.setZoom(zoom * previousZoom);\n    }\n\n    return {\n        center: view.getCenter(),\n        zoom: view.getZoom()\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {string} [componentType=series]\n * @property {number} [dx]\n * @property {number} [dy]\n * @property {number} [zoom]\n * @property {number} [originX]\n * @property {number} [originY]\n */\nregisterAction({\n    type: 'geoRoam',\n    event: 'geoRoam',\n    update: 'updateTransform'\n}, function (payload, ecModel) {\n    var componentType = payload.componentType || 'series';\n\n    ecModel.eachComponent(\n        { mainType: componentType, query: payload },\n        function (componentModel) {\n            var geo = componentModel.coordinateSystem;\n            if (geo.type !== 'geo') {\n                return;\n            }\n\n            var res = updateCenterAndZoom(\n                geo, payload, componentModel.get('scaleLimit')\n            );\n\n            componentModel.setCenter\n                && componentModel.setCenter(res.center);\n\n            componentModel.setZoom\n                && componentModel.setZoom(res.zoom);\n\n            // All map series with same `map` use the same geo coordinate system\n            // So the center and zoom must be in sync. Include the series not selected by legend\n            if (componentType === 'series') {\n                each$1(componentModel.seriesGroup, function (seriesModel) {\n                    seriesModel.setCenter(res.center);\n                    seriesModel.setZoom(res.zoom);\n                });\n            }\n        }\n    );\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Simple view coordinate system\n * Mapping given x, y to transformd view x, y\n */\n\nvar v2ApplyTransform$1 = applyTransform;\n\n// Dummy transform node\nfunction TransformDummy() {\n    Transformable.call(this);\n}\nmixin(TransformDummy, Transformable);\n\nfunction View(name) {\n    /**\n     * @type {string}\n     */\n    this.name = name;\n\n    /**\n     * @type {Object}\n     */\n    this.zoomLimit;\n\n    Transformable.call(this);\n\n    this._roamTransformable = new TransformDummy();\n\n    this._rawTransformable = new TransformDummy();\n\n    this._center;\n    this._zoom;\n}\n\nView.prototype = {\n\n    constructor: View,\n\n    type: 'view',\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Set bounding rect\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n\n    // PENDING to getRect\n    setBoundingRect: function (x, y, width, height) {\n        this._rect = new BoundingRect(x, y, width, height);\n        return this._rect;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // PENDING to getRect\n    getBoundingRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    setViewRect: function (x, y, width, height) {\n        this.transformTo(x, y, width, height);\n        this._viewRect = new BoundingRect(x, y, width, height);\n    },\n\n    /**\n     * Transformed to particular position and size\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var rawTransform = this._rawTransformable;\n\n        rawTransform.transform = rect.calculateTransform(\n            new BoundingRect(x, y, width, height)\n        );\n\n        rawTransform.decomposeTransform();\n\n        this._updateTransform();\n    },\n\n    /**\n     * Set center of view\n     * @param {Array.<number>} [centerCoord]\n     */\n    setCenter: function (centerCoord) {\n        if (!centerCoord) {\n            return;\n        }\n        this._center = centerCoord;\n\n        this._updateCenterAndZoom();\n    },\n\n    /**\n     * @param {number} zoom\n     */\n    setZoom: function (zoom) {\n        zoom = zoom || 1;\n\n        var zoomLimit = this.zoomLimit;\n        if (zoomLimit) {\n            if (zoomLimit.max != null) {\n                zoom = Math.min(zoomLimit.max, zoom);\n            }\n            if (zoomLimit.min != null) {\n                zoom = Math.max(zoomLimit.min, zoom);\n            }\n        }\n        this._zoom = zoom;\n\n        this._updateCenterAndZoom();\n    },\n\n    /**\n     * Get default center without roam\n     */\n    getDefaultCenter: function () {\n        // Rect before any transform\n        var rawRect = this.getBoundingRect();\n        var cx = rawRect.x + rawRect.width / 2;\n        var cy = rawRect.y + rawRect.height / 2;\n\n        return [cx, cy];\n    },\n\n    getCenter: function () {\n        return this._center || this.getDefaultCenter();\n    },\n\n    getZoom: function () {\n        return this._zoom || 1;\n    },\n\n    /**\n     * @return {Array.<number}\n     */\n    getRoamTransform: function () {\n        return this._roamTransformable.getLocalTransform();\n    },\n\n    /**\n     * Remove roam\n     */\n\n    _updateCenterAndZoom: function () {\n        // Must update after view transform updated\n        var rawTransformMatrix = this._rawTransformable.getLocalTransform();\n        var roamTransform = this._roamTransformable;\n        var defaultCenter = this.getDefaultCenter();\n        var center = this.getCenter();\n        var zoom = this.getZoom();\n\n        center = applyTransform([], center, rawTransformMatrix);\n        defaultCenter = applyTransform([], defaultCenter, rawTransformMatrix);\n\n        roamTransform.origin = center;\n        roamTransform.position = [\n            defaultCenter[0] - center[0],\n            defaultCenter[1] - center[1]\n        ];\n        roamTransform.scale = [zoom, zoom];\n\n        this._updateTransform();\n    },\n\n    /**\n     * Update transform from roam and mapLocation\n     * @private\n     */\n    _updateTransform: function () {\n        var roamTransformable = this._roamTransformable;\n        var rawTransformable = this._rawTransformable;\n\n        rawTransformable.parent = roamTransformable;\n        roamTransformable.updateTransform();\n        rawTransformable.updateTransform();\n\n        copy$1(this.transform || (this.transform = []), rawTransformable.transform || create$1());\n\n        this._rawTransform = rawTransformable.getLocalTransform();\n\n        this.invTransform = this.invTransform || [];\n        invert(this.invTransform, this.transform);\n\n        this.decomposeTransform();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getViewRect: function () {\n        return this._viewRect;\n    },\n\n    /**\n     * Get view rect after roam transform\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getViewRectAfterRoam: function () {\n        var rect = this.getBoundingRect().clone();\n        rect.applyTransform(this.transform);\n        return rect;\n    },\n\n    /**\n     * Convert a single (lon, lat) data item to (x, y) point.\n     * @param {Array.<number>} data\n     * @param {boolean} noRoam\n     * @param {Array.<number>} [out]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, noRoam, out) {\n        var transform = noRoam ? this._rawTransform : this.transform;\n        out = out || [];\n        return transform\n            ? v2ApplyTransform$1(out, data, transform)\n            : copy(out, data);\n    },\n\n    /**\n     * Convert a (x, y) point to (lon, lat) data\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToData: function (point) {\n        var invTransform = this.invTransform;\n        return invTransform\n            ? v2ApplyTransform$1([], point, invTransform)\n            : [point[0], point[1]];\n    },\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    convertToPixel: curry(doConvert$1, 'dataToPoint'),\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    convertFromPixel: curry(doConvert$1, 'pointToData'),\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    containPoint: function (point) {\n        return this.getViewRectAfterRoam().contain(point[0], point[1]);\n    }\n\n    /**\n     * @return {number}\n     */\n    // getScalarScale: function () {\n    //     // Use determinant square root of transform to mutiply scalar\n    //     var m = this.transform;\n    //     var det = Math.sqrt(Math.abs(m[0] * m[3] - m[2] * m[1]));\n    //     return det;\n    // }\n};\n\nmixin(View, Transformable);\n\nfunction doConvert$1(methodName, ecModel, finder, value) {\n    var seriesModel = finder.seriesModel;\n    var coordSys = seriesModel ? seriesModel.coordinateSystem : null; // e.g., graph.\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [Geo description]\n * For backward compatibility, the orginal interface:\n * `name, map, geoJson, specialAreas, nameMap` is kept.\n *\n * @param {string|Object} name\n * @param {string} map Map type\n *        Specify the positioned areas by left, top, width, height\n * @param {Object.<string, string>} [nameMap]\n *        Specify name alias\n * @param {boolean} [invertLongitute=true]\n */\nfunction Geo(name, map$$1, nameMap, invertLongitute) {\n\n    View.call(this, name);\n\n    /**\n     * Map type\n     * @type {string}\n     */\n    this.map = map$$1;\n\n    var source = geoSourceManager.load(map$$1, nameMap);\n\n    this._nameCoordMap = source.nameCoordMap;\n    this._regionsMap = source.regionsMap;\n    this._invertLongitute = invertLongitute == null ? true : invertLongitute;\n\n    /**\n     * @readOnly\n     */\n    this.regions = source.regions;\n\n    /**\n     * @type {module:zrender/src/core/BoundingRect}\n     */\n    this._rect = source.boundingRect;\n}\n\nGeo.prototype = {\n\n    constructor: Geo,\n\n    type: 'geo',\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['lng', 'lat'],\n\n    /**\n     * If contain given lng,lat coord\n     * @param {Array.<number>}\n     * @readOnly\n     */\n    containCoord: function (coord) {\n        var regions = this.regions;\n        for (var i = 0; i < regions.length; i++) {\n            if (regions[i].contain(coord)) {\n                return true;\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @override\n     */\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var invertLongitute = this._invertLongitute;\n\n        rect = rect.clone();\n\n        if (invertLongitute) {\n            // Longitute is inverted\n            rect.y = -rect.y - rect.height;\n        }\n\n        var rawTransformable = this._rawTransformable;\n\n        rawTransformable.transform = rect.calculateTransform(\n            new BoundingRect(x, y, width, height)\n        );\n\n        rawTransformable.decomposeTransform();\n\n        if (invertLongitute) {\n            var scale = rawTransformable.scale;\n            scale[1] = -scale[1];\n        }\n\n        rawTransformable.updateTransform();\n\n        this._updateTransform();\n    },\n\n    /**\n     * @param {string} name\n     * @return {module:echarts/coord/geo/Region}\n     */\n    getRegion: function (name) {\n        return this._regionsMap.get(name);\n    },\n\n    getRegionByCoord: function (coord) {\n        var regions = this.regions;\n        for (var i = 0; i < regions.length; i++) {\n            if (regions[i].contain(coord)) {\n                return regions[i];\n            }\n        }\n    },\n\n    /**\n     * Add geoCoord for indexing by name\n     * @param {string} name\n     * @param {Array.<number>} geoCoord\n     */\n    addGeoCoord: function (name, geoCoord) {\n        this._nameCoordMap.set(name, geoCoord);\n    },\n\n    /**\n     * Get geoCoord by name\n     * @param {string} name\n     * @return {Array.<number>}\n     */\n    getGeoCoord: function (name) {\n        return this._nameCoordMap.get(name);\n    },\n\n    /**\n     * @override\n     */\n    getBoundingRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @param {string|Array.<number>} data\n     * @param {boolean} noRoam\n     * @param {Array.<number>} [out]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, noRoam, out) {\n        if (typeof data === 'string') {\n            // Map area name to geoCoord\n            data = this.getGeoCoord(data);\n        }\n        if (data) {\n            return View.prototype.dataToPoint.call(this, data, noRoam, out);\n        }\n    },\n\n    /**\n     * @override\n     */\n    convertToPixel: curry(doConvert, 'dataToPoint'),\n\n    /**\n     * @override\n     */\n    convertFromPixel: curry(doConvert, 'pointToData')\n\n};\n\nmixin(Geo, View);\n\nfunction doConvert(methodName, ecModel, finder, value) {\n    var geoModel = finder.geoModel;\n    var seriesModel = finder.seriesModel;\n\n    var coordSys = geoModel\n        ? geoModel.coordinateSystem\n        : seriesModel\n        ? (\n            seriesModel.coordinateSystem // For map.\n            || (seriesModel.getReferringComponents('geo')[0] || {}).coordinateSystem\n        )\n        : null;\n\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Resize method bound to the geo\n * @param {module:echarts/coord/geo/GeoModel|module:echarts/chart/map/MapModel} geoModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction resizeGeo(geoModel, api) {\n\n    var boundingCoords = geoModel.get('boundingCoords');\n    if (boundingCoords != null) {\n        var leftTop = boundingCoords[0];\n        var rightBottom = boundingCoords[1];\n        if (isNaN(leftTop[0]) || isNaN(leftTop[1]) || isNaN(rightBottom[0]) || isNaN(rightBottom[1])) {\n            if (__DEV__) {\n                console.error('Invalid boundingCoords');\n            }\n        }\n        else {\n            this.setBoundingRect(leftTop[0], leftTop[1], rightBottom[0] - leftTop[0], rightBottom[1] - leftTop[1]);\n        }\n    }\n\n    var rect = this.getBoundingRect();\n\n    var boxLayoutOption;\n\n    var center = geoModel.get('layoutCenter');\n    var size = geoModel.get('layoutSize');\n\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n\n    var aspect = rect.width / rect.height * this.aspectScale;\n\n    var useCenterAndSize = false;\n\n    if (center && size) {\n        center = [\n            parsePercent$1(center[0], viewWidth),\n            parsePercent$1(center[1], viewHeight)\n        ];\n        size = parsePercent$1(size, Math.min(viewWidth, viewHeight));\n\n        if (!isNaN(center[0]) && !isNaN(center[1]) && !isNaN(size)) {\n            useCenterAndSize = true;\n        }\n        else {\n            if (__DEV__) {\n                console.warn('Given layoutCenter or layoutSize data are invalid. Use left/top/width/height instead.');\n            }\n        }\n    }\n\n    var viewRect;\n    if (useCenterAndSize) {\n        var viewRect = {};\n        if (aspect > 1) {\n            // Width is same with size\n            viewRect.width = size;\n            viewRect.height = size / aspect;\n        }\n        else {\n            viewRect.height = size;\n            viewRect.width = size * aspect;\n        }\n        viewRect.y = center[1] - viewRect.height / 2;\n        viewRect.x = center[0] - viewRect.width / 2;\n    }\n    else {\n        // Use left/top/width/height\n        boxLayoutOption = geoModel.getBoxLayoutParams();\n\n        // 0.75 rate\n        boxLayoutOption.aspect = aspect;\n\n        viewRect = getLayoutRect(boxLayoutOption, {\n            width: viewWidth,\n            height: viewHeight\n        });\n    }\n\n    this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);\n\n    this.setCenter(geoModel.get('center'));\n    this.setZoom(geoModel.get('zoom'));\n}\n\n/**\n * @param {module:echarts/coord/Geo} geo\n * @param {module:echarts/model/Model} model\n * @inner\n */\nfunction setGeoCoords(geo, model) {\n    each$1(model.get('geoCoord'), function (geoCoord, name) {\n        geo.addGeoCoord(name, geoCoord);\n    });\n}\n\nvar geoCreator = {\n\n    // For deciding which dimensions to use when creating list data\n    dimensions: Geo.prototype.dimensions,\n\n    create: function (ecModel, api) {\n        var geoList = [];\n\n        // FIXME Create each time may be slow\n        ecModel.eachComponent('geo', function (geoModel, idx) {\n            var name = geoModel.get('map');\n\n            var aspectScale = geoModel.get('aspectScale');\n            var invertLongitute = true;\n            var mapRecords = mapDataStorage.retrieveMap(name);\n            if (mapRecords && mapRecords[0] && mapRecords[0].type === 'svg') {\n                aspectScale == null && (aspectScale = 1);\n                invertLongitute = false;\n            }\n            else {\n                aspectScale == null && (aspectScale = 0.75);\n            }\n\n            var geo = new Geo(name + idx, name, geoModel.get('nameMap'), invertLongitute);\n\n            geo.aspectScale = aspectScale;\n            geo.zoomLimit = geoModel.get('scaleLimit');\n            geoList.push(geo);\n\n            setGeoCoords(geo, geoModel);\n\n            geoModel.coordinateSystem = geo;\n            geo.model = geoModel;\n\n            // Inject resize method\n            geo.resize = resizeGeo;\n\n            geo.resize(geoModel, api);\n        });\n\n        ecModel.eachSeries(function (seriesModel) {\n            var coordSys = seriesModel.get('coordinateSystem');\n            if (coordSys === 'geo') {\n                var geoIndex = seriesModel.get('geoIndex') || 0;\n                seriesModel.coordinateSystem = geoList[geoIndex];\n            }\n        });\n\n        // If has map series\n        var mapModelGroupBySeries = {};\n\n        ecModel.eachSeriesByType('map', function (seriesModel) {\n            if (!seriesModel.getHostGeoModel()) {\n                var mapType = seriesModel.getMapType();\n                mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || [];\n                mapModelGroupBySeries[mapType].push(seriesModel);\n            }\n        });\n\n        each$1(mapModelGroupBySeries, function (mapSeries, mapType) {\n            var nameMapList = map(mapSeries, function (singleMapSeries) {\n                return singleMapSeries.get('nameMap');\n            });\n            var geo = new Geo(mapType, mapType, mergeAll(nameMapList));\n\n            geo.zoomLimit = retrieve.apply(null, map(mapSeries, function (singleMapSeries) {\n                return singleMapSeries.get('scaleLimit');\n            }));\n            geoList.push(geo);\n\n            // Inject resize method\n            geo.resize = resizeGeo;\n            geo.aspectScale = mapSeries[0].get('aspectScale');\n\n            geo.resize(mapSeries[0], api);\n\n            each$1(mapSeries, function (singleMapSeries) {\n                singleMapSeries.coordinateSystem = geo;\n\n                setGeoCoords(geo, singleMapSeries);\n            });\n        });\n\n        return geoList;\n    },\n\n    /**\n     * Fill given regions array\n     * @param  {Array.<Object>} originRegionArr\n     * @param  {string} mapName\n     * @param  {Object} [nameMap]\n     * @return {Array}\n     */\n    getFilledRegions: function (originRegionArr, mapName, nameMap) {\n        // Not use the original\n        var regionsArr = (originRegionArr || []).slice();\n\n        var dataNameMap = createHashMap();\n        for (var i = 0; i < regionsArr.length; i++) {\n            dataNameMap.set(regionsArr[i].name, regionsArr[i]);\n        }\n\n        var source = geoSourceManager.load(mapName, nameMap);\n        each$1(source.regions, function (region) {\n            var name = region.name;\n            !dataNameMap.get(name) && regionsArr.push({name: name});\n        });\n\n        return regionsArr;\n    }\n};\n\nregisterCoordinateSystem('geo', geoCreator);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar mapSymbolLayout = function (ecModel) {\n\n    var processedMapType = {};\n\n    ecModel.eachSeriesByType('map', function (mapSeries) {\n        var mapType = mapSeries.getMapType();\n        if (mapSeries.getHostGeoModel() || processedMapType[mapType]) {\n            return;\n        }\n\n        var mapSymbolOffsets = {};\n\n        each$1(mapSeries.seriesGroup, function (subMapSeries) {\n            var geo = subMapSeries.coordinateSystem;\n            var data = subMapSeries.originalData;\n            if (subMapSeries.get('showLegendSymbol') && ecModel.getComponent('legend')) {\n                data.each(data.mapDimension('value'), function (value, idx) {\n                    var name = data.getName(idx);\n                    var region = geo.getRegion(name);\n\n                    // If input series.data is [11, 22, '-'/null/undefined, 44],\n                    // it will be filled with NaN: [11, 22, NaN, 44] and NaN will\n                    // not be drawn. So here must validate if value is NaN.\n                    if (!region || isNaN(value)) {\n                        return;\n                    }\n\n                    var offset = mapSymbolOffsets[name] || 0;\n\n                    var point = geo.dataToPoint(region.center);\n\n                    mapSymbolOffsets[name] = offset + 1;\n\n                    data.setItemLayout(idx, {\n                        point: point,\n                        offset: offset\n                    });\n                });\n            }\n        });\n\n        // Show label of those region not has legendSymbol(which is offset 0)\n        var data = mapSeries.getData();\n        data.each(function (idx) {\n            var name = data.getName(idx);\n            var layout = data.getItemLayout(idx) || {};\n            layout.showLabel = !mapSymbolOffsets[name];\n            data.setItemLayout(idx, layout);\n        });\n\n        processedMapType[mapType] = true;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar mapVisual = function (ecModel) {\n    ecModel.eachSeriesByType('map', function (seriesModel) {\n        var colorList = seriesModel.get('color');\n        var itemStyleModel = seriesModel.getModel('itemStyle');\n\n        var areaColor = itemStyleModel.get('areaColor');\n        var color = itemStyleModel.get('color')\n            || colorList[seriesModel.seriesIndex % colorList.length];\n\n        seriesModel.getData().setVisual({\n            'areaColor': areaColor,\n            'color': color\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME 公用？\n/**\n * @param {Array.<module:echarts/data/List>} datas\n * @param {string} statisticType 'average' 'sum'\n * @inner\n */\nfunction dataStatistics(datas, statisticType) {\n    var dataNameMap = {};\n\n    each$1(datas, function (data) {\n        data.each(data.mapDimension('value'), function (value, idx) {\n            // Add prefix to avoid conflict with Object.prototype.\n            var mapKey = 'ec-' + data.getName(idx);\n            dataNameMap[mapKey] = dataNameMap[mapKey] || [];\n            if (!isNaN(value)) {\n                dataNameMap[mapKey].push(value);\n            }\n        });\n    });\n\n    return datas[0].map(datas[0].mapDimension('value'), function (value, idx) {\n        var mapKey = 'ec-' + datas[0].getName(idx);\n        var sum = 0;\n        var min = Infinity;\n        var max = -Infinity;\n        var len = dataNameMap[mapKey].length;\n        for (var i = 0; i < len; i++) {\n            min = Math.min(min, dataNameMap[mapKey][i]);\n            max = Math.max(max, dataNameMap[mapKey][i]);\n            sum += dataNameMap[mapKey][i];\n        }\n        var result;\n        if (statisticType === 'min') {\n            result = min;\n        }\n        else if (statisticType === 'max') {\n            result = max;\n        }\n        else if (statisticType === 'average') {\n            result = sum / len;\n        }\n        else {\n            result = sum;\n        }\n        return len === 0 ? NaN : result;\n    });\n}\n\nvar mapDataStatistic = function (ecModel) {\n    var seriesGroups = {};\n    ecModel.eachSeriesByType('map', function (seriesModel) {\n        var hostGeoModel = seriesModel.getHostGeoModel();\n        var key = hostGeoModel ? 'o' + hostGeoModel.id : 'i' + seriesModel.getMapType();\n        (seriesGroups[key] = seriesGroups[key] || []).push(seriesModel);\n    });\n\n    each$1(seriesGroups, function (seriesList, key) {\n        var data = dataStatistics(\n            map(seriesList, function (seriesModel) {\n                return seriesModel.getData();\n            }),\n            seriesList[0].get('mapValueCalculation')\n        );\n\n        for (var i = 0; i < seriesList.length; i++) {\n            seriesList[i].originalData = seriesList[i].getData();\n        }\n\n        // FIXME Put where?\n        for (var i = 0; i < seriesList.length; i++) {\n            seriesList[i].seriesGroup = seriesList;\n            seriesList[i].needsDrawMap = i === 0 && !seriesList[i].getHostGeoModel();\n\n            seriesList[i].setData(data.cloneShallow());\n            seriesList[i].mainSeries = seriesList[0];\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar backwardCompat$2 = function (option) {\n    // Save geoCoord\n    var mapSeries = [];\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'map') {\n            mapSeries.push(seriesOpt);\n            seriesOpt.map = seriesOpt.map || seriesOpt.mapType;\n            // Put x, y, width, height, x2, y2 in the top level\n            defaults(seriesOpt, seriesOpt.mapLocation);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(mapSymbolLayout);\nregisterVisual(mapVisual);\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, mapDataStatistic);\nregisterPreprocessor(backwardCompat$2);\n\ncreateDataSelectAction('map', [{\n    type: 'mapToggleSelect',\n    event: 'mapselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'mapSelect',\n    event: 'mapselected',\n    method: 'select'\n}, {\n    type: 'mapUnSelect',\n    event: 'mapunselected',\n    method: 'unSelect'\n}]);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Link lists and struct (graph or tree)\n */\n\nvar each$7 = each$1;\n\nvar DATAS = '\\0__link_datas';\nvar MAIN_DATA = '\\0__link_mainData';\n\n// Caution:\n// In most case, either list or its shallow clones (see list.cloneShallow)\n// is active in echarts process. So considering heap memory consumption,\n// we do not clone tree or graph, but share them among list and its shallow clones.\n// But in some rare case, we have to keep old list (like do animation in chart). So\n// please take care that both the old list and the new list share the same tree/graph.\n\n/**\n * @param {Object} opt\n * @param {module:echarts/data/List} opt.mainData\n * @param {Object} [opt.struct] For example, instance of Graph or Tree.\n * @param {string} [opt.structAttr] designation: list[structAttr] = struct;\n * @param {Object} [opt.datas] {dataType: data},\n *                 like: {node: nodeList, edge: edgeList}.\n *                 Should contain mainData.\n * @param {Object} [opt.datasAttr] {dataType: attr},\n *                 designation: struct[datasAttr[dataType]] = list;\n */\nfunction linkList(opt) {\n    var mainData = opt.mainData;\n    var datas = opt.datas;\n\n    if (!datas) {\n        datas = {main: mainData};\n        opt.datasAttr = {main: 'data'};\n    }\n    opt.datas = opt.mainData = null;\n\n    linkAll(mainData, datas, opt);\n\n    // Porxy data original methods.\n    each$7(datas, function (data) {\n        each$7(mainData.TRANSFERABLE_METHODS, function (methodName) {\n            data.wrapMethod(methodName, curry(transferInjection, opt));\n        });\n\n    });\n\n    // Beyond transfer, additional features should be added to `cloneShallow`.\n    mainData.wrapMethod('cloneShallow', curry(cloneShallowInjection, opt));\n\n    // Only mainData trigger change, because struct.update may trigger\n    // another changable methods, which may bring about dead lock.\n    each$7(mainData.CHANGABLE_METHODS, function (methodName) {\n        mainData.wrapMethod(methodName, curry(changeInjection, opt));\n    });\n\n    // Make sure datas contains mainData.\n    assert$1(datas[mainData.dataType] === mainData);\n}\n\nfunction transferInjection(opt, res) {\n    if (isMainData(this)) {\n        // Transfer datas to new main data.\n        var datas = extend({}, this[DATAS]);\n        datas[this.dataType] = res;\n        linkAll(res, datas, opt);\n    }\n    else {\n        // Modify the reference in main data to point newData.\n        linkSingle(res, this.dataType, this[MAIN_DATA], opt);\n    }\n    return res;\n}\n\nfunction changeInjection(opt, res) {\n    opt.struct && opt.struct.update(this);\n    return res;\n}\n\nfunction cloneShallowInjection(opt, res) {\n    // cloneShallow, which brings about some fragilities, may be inappropriate\n    // to be exposed as an API. So for implementation simplicity we can make\n    // the restriction that cloneShallow of not-mainData should not be invoked\n    // outside, but only be invoked here.\n    each$7(res[DATAS], function (data, dataType) {\n        data !== res && linkSingle(data.cloneShallow(), dataType, res, opt);\n    });\n    return res;\n}\n\n/**\n * Supplement method to List.\n *\n * @public\n * @param {string} [dataType] If not specified, return mainData.\n * @return {module:echarts/data/List}\n */\nfunction getLinkedData(dataType) {\n    var mainData = this[MAIN_DATA];\n    return (dataType == null || mainData == null)\n        ? mainData\n        : mainData[DATAS][dataType];\n}\n\nfunction isMainData(data) {\n    return data[MAIN_DATA] === data;\n}\n\nfunction linkAll(mainData, datas, opt) {\n    mainData[DATAS] = {};\n    each$7(datas, function (data, dataType) {\n        linkSingle(data, dataType, mainData, opt);\n    });\n}\n\nfunction linkSingle(data, dataType, mainData, opt) {\n    mainData[DATAS][dataType] = data;\n    data[MAIN_DATA] = mainData;\n    data.dataType = dataType;\n\n    if (opt.struct) {\n        data[opt.structAttr] = opt.struct;\n        opt.struct[opt.datasAttr[dataType]] = data;\n    }\n\n    // Supplement method.\n    data.getLinkedData = getLinkedData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Tree data structure\n *\n * @module echarts/data/Tree\n */\n\n/**\n * @constructor module:echarts/data/Tree~TreeNode\n * @param {string} name\n * @param {module:echarts/data/Tree} hostTree\n */\nvar TreeNode = function (name, hostTree) {\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n\n    /**\n     * Depth of node\n     *\n     * @type {number}\n     * @readOnly\n     */\n    this.depth = 0;\n\n    /**\n     * Height of the subtree rooted at this node.\n     * @type {number}\n     * @readOnly\n     */\n    this.height = 0;\n\n    /**\n     * @type {module:echarts/data/Tree~TreeNode}\n     * @readOnly\n     */\n    this.parentNode = null;\n\n    /**\n     * Reference to list item.\n     * Do not persistent dataIndex outside,\n     * besause it may be changed by list.\n     * If dataIndex -1,\n     * this node is logical deleted (filtered) in list.\n     *\n     * @type {Object}\n     * @readOnly\n     */\n    this.dataIndex = -1;\n\n    /**\n     * @type {Array.<module:echarts/data/Tree~TreeNode>}\n     * @readOnly\n     */\n    this.children = [];\n\n    /**\n     * @type {Array.<module:echarts/data/Tree~TreeNode>}\n     * @pubilc\n     */\n    this.viewChildren = [];\n\n    /**\n     * @type {moduel:echarts/data/Tree}\n     * @readOnly\n     */\n    this.hostTree = hostTree;\n};\n\nTreeNode.prototype = {\n\n    constructor: TreeNode,\n\n    /**\n     * The node is removed.\n     * @return {boolean} is removed.\n     */\n    isRemoved: function () {\n        return this.dataIndex < 0;\n    },\n\n    /**\n     * Travel this subtree (include this node).\n     * Usage:\n     *    node.eachNode(function () { ... }); // preorder\n     *    node.eachNode('preorder', function () { ... }); // preorder\n     *    node.eachNode('postorder', function () { ... }); // postorder\n     *    node.eachNode(\n     *        {order: 'postorder', attr: 'viewChildren'},\n     *        function () { ... }\n     *    ); // postorder\n     *\n     * @param {(Object|string)} options If string, means order.\n     * @param {string=} options.order 'preorder' or 'postorder'\n     * @param {string=} options.attr 'children' or 'viewChildren'\n     * @param {Function} cb If in preorder and return false,\n     *                      its subtree will not be visited.\n     * @param {Object} [context]\n     */\n    eachNode: function (options, cb, context) {\n        if (typeof options === 'function') {\n            context = cb;\n            cb = options;\n            options = null;\n        }\n\n        options = options || {};\n        if (isString(options)) {\n            options = {order: options};\n        }\n\n        var order = options.order || 'preorder';\n        var children = this[options.attr || 'children'];\n\n        var suppressVisitSub;\n        order === 'preorder' && (suppressVisitSub = cb.call(context, this));\n\n        for (var i = 0; !suppressVisitSub && i < children.length; i++) {\n            children[i].eachNode(options, cb, context);\n        }\n\n        order === 'postorder' && cb.call(context, this);\n    },\n\n    /**\n     * Update depth and height of this subtree.\n     *\n     * @param  {number} depth\n     */\n    updateDepthAndHeight: function (depth) {\n        var height = 0;\n        this.depth = depth;\n        for (var i = 0; i < this.children.length; i++) {\n            var child = this.children[i];\n            child.updateDepthAndHeight(depth + 1);\n            if (child.height > height) {\n                height = child.height;\n            }\n        }\n        this.height = height + 1;\n    },\n\n    /**\n     * @param  {string} id\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeById: function (id) {\n        if (this.getId() === id) {\n            return this;\n        }\n        for (var i = 0, children = this.children, len = children.length; i < len; i++) {\n            var res = children[i].getNodeById(id);\n            if (res) {\n                return res;\n            }\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~TreeNode} node\n     * @return {boolean}\n     */\n    contains: function (node) {\n        if (node === this) {\n            return true;\n        }\n        for (var i = 0, children = this.children, len = children.length; i < len; i++) {\n            var res = children[i].contains(node);\n            if (res) {\n                return res;\n            }\n        }\n    },\n\n    /**\n     * @param {boolean} includeSelf Default false.\n     * @return {Array.<module:echarts/data/Tree~TreeNode>} order: [root, child, grandchild, ...]\n     */\n    getAncestors: function (includeSelf) {\n        var ancestors = [];\n        var node = includeSelf ? this : this.parentNode;\n        while (node) {\n            ancestors.push(node);\n            node = node.parentNode;\n        }\n        ancestors.reverse();\n        return ancestors;\n    },\n\n    /**\n     * @param {string|Array=} [dimension='value'] Default 'value'. can be 0, 1, 2, 3\n     * @return {number} Value.\n     */\n    getValue: function (dimension) {\n        var data = this.hostTree.data;\n        return data.get(data.getDimension(dimension || 'value'), this.dataIndex);\n    },\n\n    /**\n     * @param {Object} layout\n     * @param {boolean=} [merge=false]\n     */\n    setLayout: function (layout, merge$$1) {\n        this.dataIndex >= 0\n            && this.hostTree.data.setItemLayout(this.dataIndex, layout, merge$$1);\n    },\n\n    /**\n     * @return {Object} layout\n     */\n    getLayout: function () {\n        return this.hostTree.data.getItemLayout(this.dataIndex);\n    },\n\n    /**\n     * @param {string} [path]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path) {\n        if (this.dataIndex < 0) {\n            return;\n        }\n        var hostTree = this.hostTree;\n        var itemModel = hostTree.data.getItemModel(this.dataIndex);\n        var levelModel = this.getLevelModel();\n        var leavesModel;\n        if (!levelModel && (this.children.length === 0 || (this.children.length !== 0 && this.isExpand === false))) {\n            leavesModel = this.getLeavesModel();\n        }\n        return itemModel.getModel(path, (levelModel || leavesModel || hostTree.hostModel).getModel(path));\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getLevelModel: function () {\n        return (this.hostTree.levelModels || [])[this.depth];\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getLeavesModel: function () {\n        return this.hostTree.leavesModel;\n    },\n\n    /**\n     * @example\n     *  setItemVisual('color', color);\n     *  setItemVisual({\n     *      'color': color\n     *  });\n     */\n    setVisual: function (key, value) {\n        this.dataIndex >= 0\n            && this.hostTree.data.setItemVisual(this.dataIndex, key, value);\n    },\n\n    /**\n     * Get item visual\n     */\n    getVisual: function (key, ignoreParent) {\n        return this.hostTree.data.getItemVisual(this.dataIndex, key, ignoreParent);\n    },\n\n    /**\n     * @public\n     * @return {number}\n     */\n    getRawIndex: function () {\n        return this.hostTree.data.getRawIndex(this.dataIndex);\n    },\n\n    /**\n     * @public\n     * @return {string}\n     */\n    getId: function () {\n        return this.hostTree.data.getId(this.dataIndex);\n    },\n\n    /**\n     * if this is an ancestor of another node\n     *\n     * @public\n     * @param {TreeNode} node another node\n     * @return {boolean} if is ancestor\n     */\n    isAncestorOf: function (node) {\n        var parent = node.parentNode;\n        while (parent) {\n            if (parent === this) {\n                return true;\n            }\n            parent = parent.parentNode;\n        }\n        return false;\n    },\n\n    /**\n     * if this is an descendant of another node\n     *\n     * @public\n     * @param {TreeNode} node another node\n     * @return {boolean} if is descendant\n     */\n    isDescendantOf: function (node) {\n        return node !== this && node.isAncestorOf(this);\n    }\n};\n\n/**\n * @constructor\n * @alias module:echarts/data/Tree\n * @param {module:echarts/model/Model} hostModel\n * @param {Array.<Object>} levelOptions\n * @param {Object} leavesOption\n */\nfunction Tree(hostModel, levelOptions, leavesOption) {\n    /**\n     * @type {module:echarts/data/Tree~TreeNode}\n     * @readOnly\n     */\n    this.root;\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.data;\n\n    /**\n     * Index of each item is the same as the raw index of coresponding list item.\n     * @private\n     * @type {Array.<module:echarts/data/Tree~TreeNode}\n     */\n    this._nodes = [];\n\n    /**\n     * @private\n     * @readOnly\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @private\n     * @readOnly\n     * @type {Array.<module:echarts/model/Model}\n     */\n    this.levelModels = map(levelOptions || [], function (levelDefine) {\n        return new Model(levelDefine, hostModel, hostModel.ecModel);\n    });\n\n    this.leavesModel = new Model(leavesOption || {}, hostModel, hostModel.ecModel);\n}\n\nTree.prototype = {\n\n    constructor: Tree,\n\n    type: 'tree',\n\n    /**\n     * Travel this subtree (include this node).\n     * Usage:\n     *    node.eachNode(function () { ... }); // preorder\n     *    node.eachNode('preorder', function () { ... }); // preorder\n     *    node.eachNode('postorder', function () { ... }); // postorder\n     *    node.eachNode(\n     *        {order: 'postorder', attr: 'viewChildren'},\n     *        function () { ... }\n     *    ); // postorder\n     *\n     * @param {(Object|string)} options If string, means order.\n     * @param {string=} options.order 'preorder' or 'postorder'\n     * @param {string=} options.attr 'children' or 'viewChildren'\n     * @param {Function} cb\n     * @param {Object}   [context]\n     */\n    eachNode: function (options, cb, context) {\n        this.root.eachNode(options, cb, context);\n    },\n\n    /**\n     * @param {number} dataIndex\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeByDataIndex: function (dataIndex) {\n        var rawIndex = this.data.getRawIndex(dataIndex);\n        return this._nodes[rawIndex];\n    },\n\n    /**\n     * @param {string} name\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeByName: function (name) {\n        return this.root.getNodeByName(name);\n    },\n\n    /**\n     * Update item available by list,\n     * when list has been performed options like 'filterSelf' or 'map'.\n     */\n    update: function () {\n        var data = this.data;\n        var nodes = this._nodes;\n\n        for (var i = 0, len = nodes.length; i < len; i++) {\n            nodes[i].dataIndex = -1;\n        }\n\n        for (var i = 0, len = data.count(); i < len; i++) {\n            nodes[data.getRawIndex(i)].dataIndex = i;\n        }\n    },\n\n    /**\n     * Clear all layouts\n     */\n    clearLayouts: function () {\n        this.data.clearItemLayouts();\n    }\n};\n\n/**\n * data node format:\n * {\n *     name: ...\n *     value: ...\n *     children: [\n *         {\n *             name: ...\n *             value: ...\n *             children: ...\n *         },\n *         ...\n *     ]\n * }\n *\n * @static\n * @param {Object} dataRoot Root node.\n * @param {module:echarts/model/Model} hostModel\n * @param {Object} treeOptions\n * @param {Array.<Object>} treeOptions.levels\n * @param {Array.<Object>} treeOptions.leaves\n * @return module:echarts/data/Tree\n */\nTree.createTree = function (dataRoot, hostModel, treeOptions) {\n\n    var tree = new Tree(hostModel, treeOptions.levels, treeOptions.leaves);\n    var listData = [];\n    var dimMax = 1;\n\n    buildHierarchy(dataRoot);\n\n    function buildHierarchy(dataNode, parentNode) {\n        var value = dataNode.value;\n        dimMax = Math.max(dimMax, isArray(value) ? value.length : 1);\n\n        listData.push(dataNode);\n\n        var node = new TreeNode(dataNode.name, tree);\n        parentNode\n            ? addChild(node, parentNode)\n            : (tree.root = node);\n\n        tree._nodes.push(node);\n\n        var children = dataNode.children;\n        if (children) {\n            for (var i = 0; i < children.length; i++) {\n                buildHierarchy(children[i], node);\n            }\n        }\n    }\n\n    tree.root.updateDepthAndHeight(0);\n\n    var dimensionsInfo = createDimensions(listData, {\n        coordDimensions: ['value'],\n        dimensionsCount: dimMax\n    });\n\n    var list = new List(dimensionsInfo, hostModel);\n    list.initData(listData);\n\n    linkList({\n        mainData: list,\n        struct: tree,\n        structAttr: 'tree'\n    });\n\n    tree.update();\n\n    return tree;\n};\n\n/**\n * It is needed to consider the mess of 'list', 'hostModel' when creating a TreeNote,\n * so this function is not ready and not necessary to be public.\n *\n * @param {(module:echarts/data/Tree~TreeNode|Object)} child\n */\nfunction addChild(child, node) {\n    var children = node.children;\n    if (child.parentNode === node) {\n        return;\n    }\n\n    children.push(child);\n    child.parentNode = node;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Create data struct and define tree view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nSeriesModel.extend({\n\n    type: 'series.tree',\n\n    layoutInfo: null,\n\n    // can support the position parameters 'left', 'top','right','bottom', 'width',\n    // 'height' in the setOption() with 'merge' mode normal.\n    layoutMode: 'box',\n\n    /**\n     * Init a tree data structure from data in option series\n     * @param  {Object} option  the object used to config echarts view\n     * @return {module:echarts/data/List} storage initial data\n     */\n    getInitialData: function (option) {\n\n        //create an virtual root\n        var root = {name: option.name, children: option.data};\n\n        var leaves = option.leaves || {};\n\n        var treeOption = {};\n\n        treeOption.leaves = leaves;\n\n        var tree = Tree.createTree(root, this, treeOption);\n\n        var treeDepth = 0;\n\n        tree.eachNode('preorder', function (node) {\n            if (node.depth > treeDepth) {\n                treeDepth = node.depth;\n            }\n        });\n\n        var expandAndCollapse = option.expandAndCollapse;\n        var expandTreeDepth = (expandAndCollapse && option.initialTreeDepth >= 0)\n            ? option.initialTreeDepth : treeDepth;\n\n        tree.root.eachNode('preorder', function (node) {\n            var item = node.hostTree.data.getRawDataItem(node.dataIndex);\n            // Add item.collapsed != null, because users can collapse node original in the series.data.\n            node.isExpand = (item && item.collapsed != null)\n                ? !item.collapsed\n                : node.depth <= expandTreeDepth;\n        });\n\n        return tree.data;\n    },\n\n    /**\n     * Make the configuration 'orient' backward compatibly, with 'horizontal = LR', 'vertical = TB'.\n     * @returns {string} orient\n     */\n    getOrient: function () {\n        var orient = this.get('orient');\n        if (orient === 'horizontal') {\n            orient = 'LR';\n        }\n        else if (orient === 'vertical') {\n            orient = 'TB';\n        }\n        return orient;\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex\n     */\n    formatTooltip: function (dataIndex) {\n        var tree = this.getData().tree;\n        var realRoot = tree.root.children[0];\n        var node = tree.getNodeByDataIndex(dataIndex);\n        var value = node.getValue();\n        var name = node.name;\n        while (node && (node !== realRoot)) {\n            name = node.parentNode.name + '.' + name;\n            node = node.parentNode;\n        }\n        return encodeHTML(name + (\n            (isNaN(value) || value == null) ? '' : ' : ' + value\n        ));\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'view',\n\n        // the position of the whole view\n        left: '12%',\n        top: '12%',\n        right: '12%',\n        bottom: '12%',\n\n        // the layout of the tree, two value can be selected, 'orthogonal' or 'radial'\n        layout: 'orthogonal',\n\n        roam: false, // true | false | 'move' | 'scale', see module:component/helper/RoamController.\n        // Symbol size scale ratio in roam\n        nodeScaleRatio: 0.4,\n\n        // Default on center of graph\n        center: null,\n\n        zoom: 1,\n\n        // The orient of orthoginal layout, can be setted to 'LR', 'TB', 'RL', 'BT'.\n        // and the backward compatibility configuration 'horizontal = LR', 'vertical = TB'.\n        orient: 'LR',\n\n        symbol: 'emptyCircle',\n\n        symbolSize: 7,\n\n        expandAndCollapse: true,\n\n        initialTreeDepth: 2,\n\n        lineStyle: {\n            color: '#ccc',\n            width: 1.5,\n            curveness: 0.5\n        },\n\n        itemStyle: {\n            color: 'lightsteelblue',\n            borderColor: '#c23531',\n            borderWidth: 1.5\n        },\n\n        label: {\n            show: true,\n            color: '#555'\n        },\n\n        leaves: {\n            label: {\n                show: true\n            }\n        },\n\n        animationEasing: 'linear',\n\n        animationDuration: 700,\n\n        animationDurationUpdate: 1000\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* The tree layout implementation references to d3.js\n* (https://github.com/d3/d3-hierarchy). The use of the source\n* code of this file is also subject to the terms and consitions\n* of its license (BSD-3Clause, see <echarts/src/licenses/LICENSE-d3>).\n*/\n\n/**\n * @file The layout algorithm of node-link tree diagrams. Here we using Reingold-Tilford algorithm to drawing\n *       the tree.\n * @see https://github.com/d3/d3-hierarchy\n */\n\n/**\n * Initialize all computational message for following algorithm\n * @param  {module:echarts/data/Tree~TreeNode} root   The virtual root of the tree\n */\nfunction init$2(root) {\n    root.hierNode = {\n        defaultAncestor: null,\n        ancestor: root,\n        prelim: 0,\n        modifier: 0,\n        change: 0,\n        shift: 0,\n        i: 0,\n        thread: null\n    };\n\n    var nodes = [root];\n    var node;\n    var children;\n\n    while (node = nodes.pop()) { // jshint ignore:line\n        children = node.children;\n        if (node.isExpand && children.length) {\n            var n = children.length;\n            for (var i = n - 1; i >= 0; i--) {\n                var child = children[i];\n                child.hierNode = {\n                    defaultAncestor: null,\n                    ancestor: child,\n                    prelim: 0,\n                    modifier: 0,\n                    change: 0,\n                    shift: 0,\n                    i: i,\n                    thread: null\n                };\n                nodes.push(child);\n            }\n        }\n    }\n}\n\n/**\n * Computes a preliminary x coordinate for node. Before that, this function is\n * applied recursively to the children of node, as well as the function\n * apportion(). After spacing out the children by calling executeShifts(), the\n * node is placed to the midpoint of its outermost children.\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @param {Function} separation\n */\nfunction firstWalk(node, separation) {\n    var children = node.isExpand ? node.children : [];\n    var siblings = node.parentNode.children;\n    var subtreeW = node.hierNode.i ? siblings[node.hierNode.i - 1] : null;\n    if (children.length) {\n        executeShifts(node);\n        var midPoint = (children[0].hierNode.prelim + children[children.length - 1].hierNode.prelim) / 2;\n        if (subtreeW) {\n            node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);\n            node.hierNode.modifier = node.hierNode.prelim - midPoint;\n        }\n        else {\n            node.hierNode.prelim = midPoint;\n        }\n    }\n    else if (subtreeW) {\n        node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);\n    }\n    node.parentNode.hierNode.defaultAncestor = apportion(\n        node,\n        subtreeW,\n        node.parentNode.hierNode.defaultAncestor || siblings[0],\n        separation\n    );\n}\n\n\n/**\n * Computes all real x-coordinates by summing up the modifiers recursively.\n * @param  {module:echarts/data/Tree~TreeNode} node\n */\nfunction secondWalk(node) {\n    var nodeX = node.hierNode.prelim + node.parentNode.hierNode.modifier;\n    node.setLayout({x: nodeX}, true);\n    node.hierNode.modifier += node.parentNode.hierNode.modifier;\n}\n\n\nfunction separation(cb) {\n    return arguments.length ? cb : defaultSeparation;\n}\n\n/**\n * Transform the common coordinate to radial coordinate\n * @param  {number} x\n * @param  {number} y\n * @return {Object}\n */\nfunction radialCoordinate(x, y) {\n    var radialCoor = {};\n    x -= Math.PI / 2;\n    radialCoor.x = y * Math.cos(x);\n    radialCoor.y = y * Math.sin(x);\n    return radialCoor;\n}\n\n/**\n * Get the layout position of the whole view\n * @param {module:echarts/model/Series} seriesModel  the model object of sankey series\n * @param {module:echarts/ExtensionAPI} api  provide the API list that the developer can call\n * @return {module:zrender/core/BoundingRect}  size of rect to draw the sankey view\n */\nfunction getViewRect(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\n/**\n * All other shifts, applied to the smaller subtrees between w- and w+, are\n * performed by this function.\n * @param  {module:echarts/data/Tree~TreeNode} node\n */\nfunction executeShifts(node) {\n    var children = node.children;\n    var n = children.length;\n    var shift = 0;\n    var change = 0;\n    while (--n >= 0) {\n        var child = children[n];\n        child.hierNode.prelim += shift;\n        child.hierNode.modifier += shift;\n        change += child.hierNode.change;\n        shift += child.hierNode.shift + change;\n    }\n}\n\n/**\n * The core of the algorithm. Here, a new subtree is combined with the\n * previous subtrees. Threads are used to traverse the inside and outside\n * contours of the left and right subtree up to the highest common level.\n * Whenever two nodes of the inside contours conflict, we compute the left\n * one of the greatest uncommon ancestors using the function nextAncestor()\n * and call moveSubtree() to shift the subtree and prepare the shifts of\n * smaller subtrees. Finally, we add a new thread (if necessary).\n * @param  {module:echarts/data/Tree~TreeNode} subtreeV\n * @param  {module:echarts/data/Tree~TreeNode} subtreeW\n * @param  {module:echarts/data/Tree~TreeNode} ancestor\n * @param  {Function} separation\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction apportion(subtreeV, subtreeW, ancestor, separation) {\n\n    if (subtreeW) {\n        var nodeOutRight = subtreeV;\n        var nodeInRight = subtreeV;\n        var nodeOutLeft = nodeInRight.parentNode.children[0];\n        var nodeInLeft = subtreeW;\n\n        var sumOutRight = nodeOutRight.hierNode.modifier;\n        var sumInRight = nodeInRight.hierNode.modifier;\n        var sumOutLeft = nodeOutLeft.hierNode.modifier;\n        var sumInLeft = nodeInLeft.hierNode.modifier;\n\n        while (nodeInLeft = nextRight(nodeInLeft), nodeInRight = nextLeft(nodeInRight), nodeInLeft && nodeInRight) {\n            nodeOutRight = nextRight(nodeOutRight);\n            nodeOutLeft = nextLeft(nodeOutLeft);\n            nodeOutRight.hierNode.ancestor = subtreeV;\n            var shift = nodeInLeft.hierNode.prelim + sumInLeft - nodeInRight.hierNode.prelim\n                    - sumInRight + separation(nodeInLeft, nodeInRight);\n            if (shift > 0) {\n                moveSubtree(nextAncestor(nodeInLeft, subtreeV, ancestor), subtreeV, shift);\n                sumInRight += shift;\n                sumOutRight += shift;\n            }\n            sumInLeft += nodeInLeft.hierNode.modifier;\n            sumInRight += nodeInRight.hierNode.modifier;\n            sumOutRight += nodeOutRight.hierNode.modifier;\n            sumOutLeft += nodeOutLeft.hierNode.modifier;\n        }\n        if (nodeInLeft && !nextRight(nodeOutRight)) {\n            nodeOutRight.hierNode.thread = nodeInLeft;\n            nodeOutRight.hierNode.modifier += sumInLeft - sumOutRight;\n\n        }\n        if (nodeInRight && !nextLeft(nodeOutLeft)) {\n            nodeOutLeft.hierNode.thread = nodeInRight;\n            nodeOutLeft.hierNode.modifier += sumInRight - sumOutLeft;\n            ancestor = subtreeV;\n        }\n    }\n    return ancestor;\n}\n\n/**\n * This function is used to traverse the right contour of a subtree.\n * It returns the rightmost child of node or the thread of node. The function\n * returns null if and only if node is on the highest depth of its subtree.\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextRight(node) {\n    var children = node.children;\n    return children.length && node.isExpand ? children[children.length - 1] : node.hierNode.thread;\n}\n\n/**\n * This function is used to traverse the left contour of a subtree (or a subforest).\n * It returns the leftmost child of node or the thread of node. The function\n * returns null if and only if node is on the highest depth of its subtree.\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextLeft(node) {\n    var children = node.children;\n    return children.length && node.isExpand ? children[0] : node.hierNode.thread;\n}\n\n/**\n * If nodeInLeft’s ancestor is a sibling of node, returns nodeInLeft’s ancestor.\n * Otherwise, returns the specified ancestor.\n * @param  {module:echarts/data/Tree~TreeNode} nodeInLeft\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @param  {module:echarts/data/Tree~TreeNode} ancestor\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextAncestor(nodeInLeft, node, ancestor) {\n    return nodeInLeft.hierNode.ancestor.parentNode === node.parentNode\n        ? nodeInLeft.hierNode.ancestor : ancestor;\n}\n\n/**\n * Shifts the current subtree rooted at wr. This is done by increasing prelim(w+) and modifier(w+) by shift.\n * @param  {module:echarts/data/Tree~TreeNode} wl\n * @param  {module:echarts/data/Tree~TreeNode} wr\n * @param  {number} shift [description]\n */\nfunction moveSubtree(wl, wr, shift) {\n    var change = shift / (wr.hierNode.i - wl.hierNode.i);\n    wr.hierNode.change -= change;\n    wr.hierNode.shift += shift;\n    wr.hierNode.modifier += shift;\n    wr.hierNode.prelim += shift;\n    wl.hierNode.change += change;\n}\n\nfunction defaultSeparation(node1, node2) {\n    return node1.parentNode === node2.parentNode ? 1 : 2;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file This file used to draw tree view.\n * @author Deqing Li(annong035@gmail.com)\n */\n\nextendChartView({\n\n    type: 'tree',\n\n    /**\n     * Init the chart\n     * @override\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:echarts/data/Tree}\n         */\n        this._oldTree;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this._mainGroup = new Group();\n\n        /**\n         * @private\n         * @type {module:echarts/componet/helper/RoamController}\n         */\n        this._controller = new RoamController(api.getZr());\n\n        this._controllerHost = {target: this.group};\n\n        this.group.add(this._mainGroup);\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n\n        var layoutInfo = seriesModel.layoutInfo;\n\n        var group = this._mainGroup;\n\n        var layout = seriesModel.get('layout');\n\n        if (layout === 'radial') {\n            group.attr('position', [layoutInfo.x + layoutInfo.width / 2, layoutInfo.y + layoutInfo.height / 2]);\n        }\n        else {\n            group.attr('position', [layoutInfo.x, layoutInfo.y]);\n        }\n\n        this._updateViewCoordSys(seriesModel);\n        this._updateController(seriesModel, ecModel, api);\n\n        var oldData = this._data;\n\n        var seriesScope = {\n            expandAndCollapse: seriesModel.get('expandAndCollapse'),\n            layout: layout,\n            orient: seriesModel.getOrient(),\n            curvature: seriesModel.get('lineStyle.curveness'),\n            symbolRotate: seriesModel.get('symbolRotate'),\n            symbolOffset: seriesModel.get('symbolOffset'),\n            hoverAnimation: seriesModel.get('hoverAnimation'),\n            useNameLabel: true,\n            fadeIn: true\n        };\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (symbolNeedsDraw$1(data, newIdx)) {\n                    // Create node and edge\n                    updateNode(data, newIdx, null, group, seriesModel, seriesScope);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n                if (!symbolNeedsDraw$1(data, newIdx)) {\n                    symbolEl && removeNode(oldData, oldIdx, symbolEl, group, seriesModel, seriesScope);\n                    return;\n                }\n                // Update node and edge\n                updateNode(data, newIdx, symbolEl, group, seriesModel, seriesScope);\n            })\n            .remove(function (oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n                // When remove a collapsed node of subtree, since the collapsed\n                // node haven't been initialized with a symbol element,\n                // you can't found it's symbol element through index.\n                // so if we want to remove the symbol element we should insure\n                // that the symbol element is not null.\n                if (symbolEl) {\n                    removeNode(oldData, oldIdx, symbolEl, group, seriesModel, seriesScope);\n                }\n            })\n            .execute();\n\n        this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');\n\n        this._updateNodeAndLinkScale(seriesModel);\n\n        if (seriesScope.expandAndCollapse === true) {\n            data.eachItemGraphicEl(function (el, dataIndex) {\n                el.off('click').on('click', function () {\n                    api.dispatchAction({\n                        type: 'treeExpandAndCollapse',\n                        seriesId: seriesModel.id,\n                        dataIndex: dataIndex\n                    });\n                });\n            });\n        }\n        this._data = data;\n    },\n\n    _updateViewCoordSys: function (seriesModel) {\n        var data = seriesModel.getData();\n        var points = [];\n        data.each(function (idx) {\n            var layout = data.getItemLayout(idx);\n            if (layout && !isNaN(layout.x) && !isNaN(layout.y)) {\n                points.push([+layout.x, +layout.y]);\n            }\n        });\n        var min = [];\n        var max = [];\n        fromPoints(points, min, max);\n        // If width or height is 0\n        if (max[0] - min[0] === 0) {\n            max[0] += 1;\n            min[0] -= 1;\n        }\n        if (max[1] - min[1] === 0) {\n            max[1] += 1;\n            min[1] -= 1;\n        }\n\n        var viewCoordSys = seriesModel.coordinateSystem = new View();\n        viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');\n\n        viewCoordSys.setBoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]);\n\n        viewCoordSys.setCenter(seriesModel.get('center'));\n        viewCoordSys.setZoom(seriesModel.get('zoom'));\n\n        // Here we use viewCoordSys just for computing the 'position' and 'scale' of the group\n        this.group.attr({\n            position: viewCoordSys.position,\n            scale: viewCoordSys.scale\n        });\n\n        this._viewCoordSys = viewCoordSys;\n    },\n\n    _updateController: function (seriesModel, ecModel, api) {\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n        var group = this.group;\n        controller.setPointerChecker(function (e, x, y) {\n            var rect = group.getBoundingRect();\n            rect.applyTransform(group.transform);\n            return rect.contain(x, y)\n                && !onIrrelevantElement(e, api, seriesModel);\n        });\n\n        controller.enable(seriesModel.get('roam'));\n        controllerHost.zoomLimit = seriesModel.get('scaleLimit');\n        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();\n\n        controller\n            .off('pan')\n            .off('zoom')\n            .on('pan', function (e) {\n                updateViewOnPan(controllerHost, e.dx, e.dy);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'treeRoam',\n                    dx: e.dx,\n                    dy: e.dy\n                });\n            }, this)\n            .on('zoom', function (e) {\n                updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'treeRoam',\n                    zoom: e.scale,\n                    originX: e.originX,\n                    originY: e.originY\n                });\n                this._updateNodeAndLinkScale(seriesModel);\n            }, this);\n    },\n\n    _updateNodeAndLinkScale: function (seriesModel) {\n        var data = seriesModel.getData();\n\n        var nodeScale = this._getNodeGlobalScale(seriesModel);\n        var invScale = [nodeScale, nodeScale];\n\n        data.eachItemGraphicEl(function (el, idx) {\n            el.attr('scale', invScale);\n        });\n    },\n\n    _getNodeGlobalScale: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type !== 'view') {\n            return 1;\n        }\n\n        var nodeScaleRatio = this._nodeScaleRatio;\n\n        var groupScale = coordSys.scale;\n        var groupZoom = (groupScale && groupScale[0]) || 1;\n        // Scale node when zoom changes\n        var roamZoom = coordSys.getZoom();\n        var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;\n\n        return nodeScale / groupZoom;\n    },\n\n    dispose: function () {\n        this._controller && this._controller.dispose();\n        this._controllerHost = {};\n    },\n\n    remove: function () {\n        this._mainGroup.removeAll();\n        this._data = null;\n    }\n\n});\n\nfunction symbolNeedsDraw$1(data, dataIndex) {\n    var layout = data.getItemLayout(dataIndex);\n\n    return layout\n        && !isNaN(layout.x) && !isNaN(layout.y)\n        && data.getItemVisual(dataIndex, 'symbol') !== 'none';\n}\n\nfunction getTreeNodeStyle(node, itemModel, seriesScope) {\n    seriesScope.itemModel = itemModel;\n    seriesScope.itemStyle = itemModel.getModel('itemStyle').getItemStyle();\n    seriesScope.hoverItemStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n    seriesScope.lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n    seriesScope.labelModel = itemModel.getModel('label');\n    seriesScope.hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    if (node.isExpand === false && node.children.length !== 0) {\n        seriesScope.symbolInnerColor = seriesScope.itemStyle.fill;\n    }\n    else {\n        seriesScope.symbolInnerColor = '#fff';\n    }\n\n    return seriesScope;\n}\n\nfunction updateNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {\n    var isInit = !symbolEl;\n    var node = data.tree.getNodeByDataIndex(dataIndex);\n    var itemModel = node.getModel();\n    var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);\n    var virtualRoot = data.tree.root;\n\n    var source = node.parentNode === virtualRoot ? node : node.parentNode || node;\n    var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex);\n    var sourceLayout = source.getLayout();\n    var sourceOldLayout = sourceSymbolEl\n        ? {\n            x: sourceSymbolEl.position[0],\n            y: sourceSymbolEl.position[1],\n            rawX: sourceSymbolEl.__radialOldRawX,\n            rawY: sourceSymbolEl.__radialOldRawY\n        }\n        : sourceLayout;\n    var targetLayout = node.getLayout();\n\n    if (isInit) {\n        symbolEl = new SymbolClz$1(data, dataIndex, seriesScope);\n        symbolEl.attr('position', [sourceOldLayout.x, sourceOldLayout.y]);\n    }\n    else {\n        symbolEl.updateData(data, dataIndex, seriesScope);\n    }\n\n    symbolEl.__radialOldRawX = symbolEl.__radialRawX;\n    symbolEl.__radialOldRawY = symbolEl.__radialRawY;\n    symbolEl.__radialRawX = targetLayout.rawX;\n    symbolEl.__radialRawY = targetLayout.rawY;\n\n    group.add(symbolEl);\n    data.setItemGraphicEl(dataIndex, symbolEl);\n    updateProps(symbolEl, {\n        position: [targetLayout.x, targetLayout.y]\n    }, seriesModel);\n\n    var symbolPath = symbolEl.getSymbolPath();\n\n    if (seriesScope.layout === 'radial') {\n        var realRoot = virtualRoot.children[0];\n        var rootLayout = realRoot.getLayout();\n        var length = realRoot.children.length;\n        var rad;\n        var isLeft;\n\n        if (targetLayout.x === rootLayout.x && node.isExpand === true) {\n            var center = {};\n            center.x = (realRoot.children[0].getLayout().x + realRoot.children[length - 1].getLayout().x) / 2;\n            center.y = (realRoot.children[0].getLayout().y + realRoot.children[length - 1].getLayout().y) / 2;\n            rad = Math.atan2(center.y - rootLayout.y, center.x - rootLayout.x);\n            if (rad < 0) {\n                rad = Math.PI * 2 + rad;\n            }\n            isLeft = center.x < rootLayout.x;\n            if (isLeft) {\n                rad = rad - Math.PI;\n            }\n        }\n        else {\n            rad = Math.atan2(targetLayout.y - rootLayout.y, targetLayout.x - rootLayout.x);\n            if (rad < 0) {\n                rad = Math.PI * 2 + rad;\n            }\n            if (node.children.length === 0 || (node.children.length !== 0 && node.isExpand === false)) {\n                isLeft = targetLayout.x < rootLayout.x;\n                if (isLeft) {\n                    rad = rad - Math.PI;\n                }\n            }\n            else {\n                isLeft = targetLayout.x > rootLayout.x;\n                if (!isLeft) {\n                    rad = rad - Math.PI;\n                }\n            }\n        }\n\n        var textPosition = isLeft ? 'left' : 'right';\n        symbolPath.setStyle({\n            textPosition: textPosition,\n            textRotation: -rad,\n            textOrigin: 'center',\n            verticalAlign: 'middle'\n        });\n    }\n\n    if (node.parentNode && node.parentNode !== virtualRoot) {\n        var edge = symbolEl.__edge;\n        if (!edge) {\n            edge = symbolEl.__edge = new BezierCurve({\n                shape: getEdgeShape(seriesScope, sourceOldLayout, sourceOldLayout),\n                style: defaults({opacity: 0, strokeNoScale: true}, seriesScope.lineStyle)\n            });\n        }\n\n        updateProps(edge, {\n            shape: getEdgeShape(seriesScope, sourceLayout, targetLayout),\n            style: {opacity: 1}\n        }, seriesModel);\n\n        group.add(edge);\n    }\n}\n\nfunction removeNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {\n    var node = data.tree.getNodeByDataIndex(dataIndex);\n    var virtualRoot = data.tree.root;\n    var itemModel = node.getModel();\n    var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);\n\n    var source = node.parentNode === virtualRoot ? node : node.parentNode || node;\n    var sourceLayout;\n    while (sourceLayout = source.getLayout(), sourceLayout == null) {\n        source = source.parentNode === virtualRoot ? source : source.parentNode || source;\n    }\n\n    updateProps(symbolEl, {\n        position: [sourceLayout.x + 1, sourceLayout.y + 1]\n    }, seriesModel, function () {\n        group.remove(symbolEl);\n        data.setItemGraphicEl(dataIndex, null);\n    });\n\n    symbolEl.fadeOut(null, {keepLabel: true});\n\n    var edge = symbolEl.__edge;\n    if (edge) {\n        updateProps(edge, {\n            shape: getEdgeShape(seriesScope, sourceLayout, sourceLayout),\n            style: {\n                opacity: 0\n            }\n        }, seriesModel, function () {\n            group.remove(edge);\n        });\n    }\n}\n\nfunction getEdgeShape(seriesScope, sourceLayout, targetLayout) {\n    var cpx1;\n    var cpy1;\n    var cpx2;\n    var cpy2;\n    var orient = seriesScope.orient;\n    var x1;\n    var x2;\n    var y1;\n    var y2;\n\n    if (seriesScope.layout === 'radial') {\n        x1 = sourceLayout.rawX;\n        y1 = sourceLayout.rawY;\n        x2 = targetLayout.rawX;\n        y2 = targetLayout.rawY;\n\n        var radialCoor1 = radialCoordinate(x1, y1);\n        var radialCoor2 = radialCoordinate(x1, y1 + (y2 - y1) * seriesScope.curvature);\n        var radialCoor3 = radialCoordinate(x2, y2 + (y1 - y2) * seriesScope.curvature);\n        var radialCoor4 = radialCoordinate(x2, y2);\n\n        return {\n            x1: radialCoor1.x,\n            y1: radialCoor1.y,\n            x2: radialCoor4.x,\n            y2: radialCoor4.y,\n            cpx1: radialCoor2.x,\n            cpy1: radialCoor2.y,\n            cpx2: radialCoor3.x,\n            cpy2: radialCoor3.y\n        };\n    }\n    else {\n        x1 = sourceLayout.x;\n        y1 = sourceLayout.y;\n        x2 = targetLayout.x;\n        y2 = targetLayout.y;\n\n        if (orient === 'LR' || orient === 'RL') {\n            cpx1 = x1 + (x2 - x1) * seriesScope.curvature;\n            cpy1 = y1;\n            cpx2 = x2 + (x1 - x2) * seriesScope.curvature;\n            cpy2 = y2;\n        }\n        if (orient === 'TB' || orient === 'BT') {\n            cpx1 = x1;\n            cpy1 = y1 + (y2 - y1) * seriesScope.curvature;\n            cpx2 = x2;\n            cpy2 = y2 + (y1 - y2) * seriesScope.curvature;\n        }\n    }\n\n    return {\n        x1: x1,\n        y1: y1,\n        x2: x2,\n        y2: y2,\n        cpx1: cpx1,\n        cpy1: cpy1,\n        cpx2: cpx2,\n        cpy2: cpy2\n    };\n\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Register the actions of the tree\n * @author Deqing Li(annong035@gmail.com)\n */\n\nregisterAction({\n    type: 'treeExpandAndCollapse',\n    event: 'treeExpandAndCollapse',\n    update: 'update'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'tree', query: payload}, function (seriesModel) {\n        var dataIndex = payload.dataIndex;\n        var tree = seriesModel.getData().tree;\n        var node = tree.getNodeByDataIndex(dataIndex);\n        node.isExpand = !node.isExpand;\n\n    });\n});\n\nregisterAction({\n    type: 'treeRoam',\n    event: 'treeRoam',\n    // Here we set 'none' instead of 'update', because roam action\n    // just need to update the transform matrix without having to recalculate\n    // the layout. So don't need to go through the whole update process, such\n    // as 'dataPrcocess', 'coordSystemUpdate', 'layout' and so on.\n    update: 'none'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'tree', query: payload}, function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        var res = updateCenterAndZoom(coordSys, payload);\n\n        seriesModel.setCenter\n            && seriesModel.setCenter(res.center);\n\n        seriesModel.setZoom\n            && seriesModel.setZoom(res.zoom);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * Traverse the tree from bottom to top and do something\n * @param  {module:echarts/data/Tree~TreeNode} root  The real root of the tree\n * @param  {Function} callback\n */\nfunction eachAfter(root, callback, separation) {\n    var nodes = [root];\n    var next = [];\n    var node;\n\n    while (node = nodes.pop()) { // jshint ignore:line\n        next.push(node);\n        if (node.isExpand) {\n            var children = node.children;\n            if (children.length) {\n                for (var i = 0; i < children.length; i++) {\n                    nodes.push(children[i]);\n                }\n            }\n        }\n    }\n\n    while (node = next.pop()) { // jshint ignore:line\n        callback(node, separation);\n    }\n}\n\n/**\n * Traverse the tree from top to bottom and do something\n * @param  {module:echarts/data/Tree~TreeNode} root  The real root of the tree\n * @param  {Function} callback\n */\nfunction eachBefore(root, callback) {\n    var nodes = [root];\n    var node;\n    while (node = nodes.pop()) { // jshint ignore:line\n        callback(node);\n        if (node.isExpand) {\n            var children = node.children;\n            if (children.length) {\n                for (var i = children.length - 1; i >= 0; i--) {\n                    nodes.push(children[i]);\n                }\n            }\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar treeLayout = function (ecModel, api) {\n    ecModel.eachSeriesByType('tree', function (seriesModel) {\n        commonLayout(seriesModel, api);\n    });\n};\n\nfunction commonLayout(seriesModel, api) {\n    var layoutInfo = getViewRect(seriesModel, api);\n    seriesModel.layoutInfo = layoutInfo;\n    var layout = seriesModel.get('layout');\n    var width = 0;\n    var height = 0;\n    var separation$$1 = null;\n\n    if (layout === 'radial') {\n        width = 2 * Math.PI;\n        height = Math.min(layoutInfo.height, layoutInfo.width) / 2;\n        separation$$1 = separation(function (node1, node2) {\n            return (node1.parentNode === node2.parentNode ? 1 : 2) / node1.depth;\n        });\n    }\n    else {\n        width = layoutInfo.width;\n        height = layoutInfo.height;\n        separation$$1 = separation();\n    }\n\n    var virtualRoot = seriesModel.getData().tree.root;\n    var realRoot = virtualRoot.children[0];\n\n    if (realRoot) {\n        init$2(virtualRoot);\n        eachAfter(realRoot, firstWalk, separation$$1);\n        virtualRoot.hierNode.modifier = -realRoot.hierNode.prelim;\n        eachBefore(realRoot, secondWalk);\n\n        var left = realRoot;\n        var right = realRoot;\n        var bottom = realRoot;\n        eachBefore(realRoot, function (node) {\n            var x = node.getLayout().x;\n            if (x < left.getLayout().x) {\n                left = node;\n            }\n            if (x > right.getLayout().x) {\n                right = node;\n            }\n            if (node.depth > bottom.depth) {\n                bottom = node;\n            }\n        });\n\n        var delta = left === right ? 1 : separation$$1(left, right) / 2;\n        var tx = delta - left.getLayout().x;\n        var kx = 0;\n        var ky = 0;\n        var coorX = 0;\n        var coorY = 0;\n        if (layout === 'radial') {\n            kx = width / (right.getLayout().x + delta + tx);\n            // here we use (node.depth - 1), bucause the real root's depth is 1\n            ky = height / ((bottom.depth - 1) || 1);\n            eachBefore(realRoot, function (node) {\n                coorX = (node.getLayout().x + tx) * kx;\n                coorY = (node.depth - 1) * ky;\n                var finalCoor = radialCoordinate(coorX, coorY);\n                node.setLayout({x: finalCoor.x, y: finalCoor.y, rawX: coorX, rawY: coorY}, true);\n            });\n        }\n        else {\n            var orient = seriesModel.getOrient();\n            if (orient === 'RL' || orient === 'LR') {\n                ky = height / (right.getLayout().x + delta + tx);\n                kx = width / ((bottom.depth - 1) || 1);\n                eachBefore(realRoot, function (node) {\n                    coorY = (node.getLayout().x + tx) * ky;\n                    coorX = orient === 'LR'\n                        ? (node.depth - 1) * kx\n                        : width - (node.depth - 1) * kx;\n                    node.setLayout({x: coorX, y: coorY}, true);\n                });\n            }\n            else if (orient === 'TB' || orient === 'BT') {\n                kx = width / (right.getLayout().x + delta + tx);\n                ky = height / ((bottom.depth - 1) || 1);\n                eachBefore(realRoot, function (node) {\n                    coorX = (node.getLayout().x + tx) * kx;\n                    coorY = orient === 'TB'\n                        ? (node.depth - 1) * ky\n                        : height - (node.depth - 1) * ky;\n                    node.setLayout({x: coorX, y: coorY}, true);\n                });\n            }\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(visualSymbol('tree', 'circle'));\nregisterLayout(treeLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction retrieveTargetInfo(payload, validPayloadTypes, seriesModel) {\n    if (payload && indexOf(validPayloadTypes, payload.type) >= 0) {\n        var root = seriesModel.getData().tree.root;\n        var targetNode = payload.targetNode;\n\n        if (typeof targetNode === 'string') {\n            targetNode = root.getNodeById(targetNode);\n        }\n\n        if (targetNode && root.contains(targetNode)) {\n            return {node: targetNode};\n        }\n\n        var targetNodeId = payload.targetNodeId;\n        if (targetNodeId != null && (targetNode = root.getNodeById(targetNodeId))) {\n            return {node: targetNode};\n        }\n    }\n}\n\n// Not includes the given node at the last item.\nfunction getPathToRoot(node) {\n    var path = [];\n    while (node) {\n        node = node.parentNode;\n        node && path.push(node);\n    }\n    return path.reverse();\n}\n\nfunction aboveViewRoot(viewRoot, node) {\n    var viewPath = getPathToRoot(viewRoot);\n    return indexOf(viewPath, node) >= 0;\n}\n\n// From root to the input node (the input node will be included).\nfunction wrapTreePathInfo(node, seriesModel) {\n    var treePathInfo = [];\n\n    while (node) {\n        var nodeDataIndex = node.dataIndex;\n        treePathInfo.push({\n            name: node.name,\n            dataIndex: nodeDataIndex,\n            value: seriesModel.getRawValue(nodeDataIndex)\n        });\n        node = node.parentNode;\n    }\n\n    treePathInfo.reverse();\n\n    return treePathInfo;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.treemap',\n\n    layoutMode: 'box',\n\n    dependencies: ['grid', 'polar'],\n\n    /**\n     * @type {module:echarts/data/Tree~Node}\n     */\n    _viewRoot: null,\n\n    defaultOption: {\n        // Disable progressive rendering\n        progressive: 0,\n        hoverLayerThreshold: Infinity,\n        // center: ['50%', '50%'],          // not supported in ec3.\n        // size: ['80%', '80%'],            // deprecated, compatible with ec2.\n        left: 'center',\n        top: 'middle',\n        right: null,\n        bottom: null,\n        width: '80%',\n        height: '80%',\n        sort: true,                         // Can be null or false or true\n                                            // (order by desc default, asc not supported yet (strange effect))\n        clipWindow: 'origin',               // Size of clipped window when zooming. 'origin' or 'fullscreen'\n        squareRatio: 0.5 * (1 + Math.sqrt(5)), // golden ratio\n        leafDepth: null,                    // Nodes on depth from root are regarded as leaves.\n                                            // Count from zero (zero represents only view root).\n        drillDownIcon: '▶',                 // Use html character temporarily because it is complicated\n                                            // to align specialized icon. ▷▶❒❐▼✚\n\n        zoomToNodeRatio: 0.32 * 0.32,       // Be effective when using zoomToNode. Specify the proportion of the\n                                            // target node area in the view area.\n        roam: true,                         // true, false, 'scale' or 'zoom', 'move'.\n        nodeClick: 'zoomToNode',            // Leaf node click behaviour: 'zoomToNode', 'link', false.\n                                            // If leafDepth is set and clicking a node which has children but\n                                            // be on left depth, the behaviour would be changing root. Otherwise\n                                            // use behavious defined above.\n        animation: true,\n        animationDurationUpdate: 900,\n        animationEasing: 'quinticInOut',\n        breadcrumb: {\n            show: true,\n            height: 22,\n            left: 'center',\n            top: 'bottom',\n            // right\n            // bottom\n            emptyItemWidth: 25,             // Width of empty node.\n            itemStyle: {\n                color: 'rgba(0,0,0,0.7)', //'#5793f3',\n                borderColor: 'rgba(255,255,255,0.7)',\n                borderWidth: 1,\n                shadowColor: 'rgba(150,150,150,1)',\n                shadowBlur: 3,\n                shadowOffsetX: 0,\n                shadowOffsetY: 0,\n                textStyle: {\n                    color: '#fff'\n                }\n            },\n            emphasis: {\n                textStyle: {}\n            }\n        },\n        label: {\n            show: true,\n            // Do not use textDistance, for ellipsis rect just the same as treemap node rect.\n            distance: 0,\n            padding: 5,\n            position: 'inside', // Can be [5, '5%'] or position stirng like 'insideTopLeft', ...\n            // formatter: null,\n            color: '#fff',\n            ellipsis: true\n            // align\n            // verticalAlign\n        },\n        upperLabel: {                   // Label when node is parent.\n            show: false,\n            position: [0, '50%'],\n            height: 20,\n            // formatter: null,\n            color: '#fff',\n            ellipsis: true,\n            // align: null,\n            verticalAlign: 'middle'\n        },\n        itemStyle: {\n            color: null,            // Can be 'none' if not necessary.\n            colorAlpha: null,       // Can be 'none' if not necessary.\n            colorSaturation: null,  // Can be 'none' if not necessary.\n            borderWidth: 0,\n            gapWidth: 0,\n            borderColor: '#fff',\n            borderColorSaturation: null // If specified, borderColor will be ineffective, and the\n                                        // border color is evaluated by color of current node and\n                                        // borderColorSaturation.\n        },\n        emphasis: {\n            upperLabel: {\n                show: true,\n                position: [0, '50%'],\n                color: '#fff',\n                ellipsis: true,\n                verticalAlign: 'middle'\n            }\n        },\n\n        visualDimension: 0,                 // Can be 0, 1, 2, 3.\n        visualMin: null,\n        visualMax: null,\n\n        color: [],                  // + treemapSeries.color should not be modified. Please only modified\n                                    // level[n].color (if necessary).\n                                    // + Specify color list of each level. level[0].color would be global\n                                    // color list if not specified. (see method `setDefault`).\n                                    // + But set as a empty array to forbid fetch color from global palette\n                                    // when using nodeModel.get('color'), otherwise nodes on deep level\n                                    // will always has color palette set and are not able to inherit color\n                                    // from parent node.\n                                    // + TreemapSeries.color can not be set as 'none', otherwise effect\n                                    // legend color fetching (see seriesColor.js).\n        colorAlpha: null,           // Array. Specify color alpha range of each level, like [0.2, 0.8]\n        colorSaturation: null,      // Array. Specify color saturation of each level, like [0.2, 0.5]\n        colorMappingBy: 'index',    // 'value' or 'index' or 'id'.\n        visibleMin: 10,             // If area less than this threshold (unit: pixel^2), node will not\n                                    // be rendered. Only works when sort is 'asc' or 'desc'.\n        childrenVisibleMin: null,   // If area of a node less than this threshold (unit: pixel^2),\n                                    // grandchildren will not show.\n                                    // Why grandchildren? If not grandchildren but children,\n                                    // some siblings show children and some not,\n                                    // the appearance may be mess and not consistent,\n        levels: []                  // Each item: {\n                                    //     visibleMin, itemStyle, visualDimension, label\n                                    // }\n        // data: {\n        //      value: [],\n        //      children: [],\n        //      link: 'http://xxx.xxx.xxx',\n        //      target: 'blank' or 'self'\n        // }\n    },\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        // Create a virtual root.\n        var root = {name: option.name, children: option.data};\n\n        completeTreeValue(root);\n\n        var levels = option.levels || [];\n\n        levels = option.levels = setDefault(levels, ecModel);\n\n        var treeOption = {};\n\n        treeOption.levels = levels;\n\n        // Make sure always a new tree is created when setOption,\n        // in TreemapView, we check whether oldTree === newTree\n        // to choose mappings approach among old shapes and new shapes.\n        return Tree.createTree(root, this, treeOption).data;\n    },\n\n    optionUpdated: function () {\n        this.resetViewRoot();\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex\n     * @param {boolean} [mutipleSeries=false]\n     */\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? addCommas(value[0]) : addCommas(value);\n        var name = data.getName(dataIndex);\n\n        return encodeHTML(name + ': ' + formattedValue);\n    },\n\n    /**\n     * Add tree path to tooltip param\n     *\n     * @override\n     * @param {number} dataIndex\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n\n        var node = this.getData().tree.getNodeByDataIndex(dataIndex);\n        params.treePathInfo = wrapTreePathInfo(node, this);\n\n        return params;\n    },\n\n    /**\n     * @public\n     * @param {Object} layoutInfo {\n     *                                x: containerGroup x\n     *                                y: containerGroup y\n     *                                width: containerGroup width\n     *                                height: containerGroup height\n     *                            }\n     */\n    setLayoutInfo: function (layoutInfo) {\n        /**\n         * @readOnly\n         * @type {Object}\n         */\n        this.layoutInfo = this.layoutInfo || {};\n        extend(this.layoutInfo, layoutInfo);\n    },\n\n    /**\n     * @param  {string} id\n     * @return {number} index\n     */\n    mapIdToIndex: function (id) {\n        // A feature is implemented:\n        // index is monotone increasing with the sequence of\n        // input id at the first time.\n        // This feature can make sure that each data item and its\n        // mapped color have the same index between data list and\n        // color list at the beginning, which is useful for user\n        // to adjust data-color mapping.\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        var idIndexMap = this._idIndexMap;\n\n        if (!idIndexMap) {\n            idIndexMap = this._idIndexMap = createHashMap();\n            /**\n             * @private\n             * @type {number}\n             */\n            this._idIndexMapCount = 0;\n        }\n\n        var index = idIndexMap.get(id);\n        if (index == null) {\n            idIndexMap.set(id, index = this._idIndexMapCount++);\n        }\n\n        return index;\n    },\n\n    getViewRoot: function () {\n        return this._viewRoot;\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~Node} [viewRoot]\n     */\n    resetViewRoot: function (viewRoot) {\n        viewRoot\n            ? (this._viewRoot = viewRoot)\n            : (viewRoot = this._viewRoot);\n\n        var root = this.getRawData().tree.root;\n\n        if (!viewRoot\n            || (viewRoot !== root && !root.contains(viewRoot))\n        ) {\n            this._viewRoot = root;\n        }\n    }\n});\n\n/**\n * @param {Object} dataNode\n */\nfunction completeTreeValue(dataNode) {\n    // Postorder travel tree.\n    // If value of none-leaf node is not set,\n    // calculate it by suming up the value of all children.\n    var sum = 0;\n\n    each$1(dataNode.children, function (child) {\n\n        completeTreeValue(child);\n\n        var childValue = child.value;\n        isArray(childValue) && (childValue = childValue[0]);\n\n        sum += childValue;\n    });\n\n    var thisValue = dataNode.value;\n    if (isArray(thisValue)) {\n        thisValue = thisValue[0];\n    }\n\n    if (thisValue == null || isNaN(thisValue)) {\n        thisValue = sum;\n    }\n    // Value should not less than 0.\n    if (thisValue < 0) {\n        thisValue = 0;\n    }\n\n    isArray(dataNode.value)\n        ? (dataNode.value[0] = thisValue)\n        : (dataNode.value = thisValue);\n}\n\n/**\n * set default to level configuration\n */\nfunction setDefault(levels, ecModel) {\n    var globalColorList = ecModel.get('color');\n\n    if (!globalColorList) {\n        return;\n    }\n\n    levels = levels || [];\n    var hasColorDefine;\n    each$1(levels, function (levelDefine) {\n        var model = new Model(levelDefine);\n        var modelColor = model.get('color');\n\n        if (model.get('itemStyle.color')\n            || (modelColor && modelColor !== 'none')\n        ) {\n            hasColorDefine = true;\n        }\n    });\n\n    if (!hasColorDefine) {\n        var level0 = levels[0] || (levels[0] = {});\n        level0.color = globalColorList.slice();\n    }\n\n    return levels;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TEXT_PADDING = 8;\nvar ITEM_GAP = 8;\nvar ARRAY_LENGTH = 5;\n\nfunction Breadcrumb(containerGroup) {\n    /**\n     * @private\n     * @type {module:zrender/container/Group}\n     */\n    this.group = new Group();\n\n    containerGroup.add(this.group);\n}\n\nBreadcrumb.prototype = {\n\n    constructor: Breadcrumb,\n\n    render: function (seriesModel, api, targetNode, onSelect) {\n        var model = seriesModel.getModel('breadcrumb');\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        if (!model.get('show') || !targetNode) {\n            return;\n        }\n\n        var normalStyleModel = model.getModel('itemStyle');\n        // var emphasisStyleModel = model.getModel('emphasis.itemStyle');\n        var textStyleModel = normalStyleModel.getModel('textStyle');\n\n        var layoutParam = {\n            pos: {\n                left: model.get('left'),\n                right: model.get('right'),\n                top: model.get('top'),\n                bottom: model.get('bottom')\n            },\n            box: {\n                width: api.getWidth(),\n                height: api.getHeight()\n            },\n            emptyItemWidth: model.get('emptyItemWidth'),\n            totalWidth: 0,\n            renderList: []\n        };\n\n        this._prepare(targetNode, layoutParam, textStyleModel);\n        this._renderContent(seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect);\n\n        positionElement(thisGroup, layoutParam.pos, layoutParam.box);\n    },\n\n    /**\n     * Prepare render list and total width\n     * @private\n     */\n    _prepare: function (targetNode, layoutParam, textStyleModel) {\n        for (var node = targetNode; node; node = node.parentNode) {\n            var text = node.getModel().get('name');\n            var textRect = textStyleModel.getTextRect(text);\n            var itemWidth = Math.max(\n                textRect.width + TEXT_PADDING * 2,\n                layoutParam.emptyItemWidth\n            );\n            layoutParam.totalWidth += itemWidth + ITEM_GAP;\n            layoutParam.renderList.push({node: node, text: text, width: itemWidth});\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderContent: function (\n        seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect\n    ) {\n        // Start rendering.\n        var lastX = 0;\n        var emptyItemWidth = layoutParam.emptyItemWidth;\n        var height = seriesModel.get('breadcrumb.height');\n        var availableSize = getAvailableSize(layoutParam.pos, layoutParam.box);\n        var totalWidth = layoutParam.totalWidth;\n        var renderList = layoutParam.renderList;\n\n        for (var i = renderList.length - 1; i >= 0; i--) {\n            var item = renderList[i];\n            var itemNode = item.node;\n            var itemWidth = item.width;\n            var text = item.text;\n\n            // Hdie text and shorten width if necessary.\n            if (totalWidth > availableSize.width) {\n                totalWidth -= itemWidth - emptyItemWidth;\n                itemWidth = emptyItemWidth;\n                text = null;\n            }\n\n            var el = new Polygon({\n                shape: {\n                    points: makeItemPoints(\n                        lastX, 0, itemWidth, height,\n                        i === renderList.length - 1, i === 0\n                    )\n                },\n                style: defaults(\n                    normalStyleModel.getItemStyle(),\n                    {\n                        lineJoin: 'bevel',\n                        text: text,\n                        textFill: textStyleModel.getTextColor(),\n                        textFont: textStyleModel.getFont()\n                    }\n                ),\n                z: 10,\n                onclick: curry(onSelect, itemNode)\n            });\n            this.group.add(el);\n\n            packEventData(el, seriesModel, itemNode);\n\n            lastX += itemWidth + ITEM_GAP;\n        }\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this.group.removeAll();\n    }\n};\n\nfunction makeItemPoints(x, y, itemWidth, itemHeight, head, tail) {\n    var points = [\n        [head ? x : x - ARRAY_LENGTH, y],\n        [x + itemWidth, y],\n        [x + itemWidth, y + itemHeight],\n        [head ? x : x - ARRAY_LENGTH, y + itemHeight]\n    ];\n    !tail && points.splice(2, 0, [x + itemWidth + ARRAY_LENGTH, y + itemHeight / 2]);\n    !head && points.push([x, y + itemHeight / 2]);\n    return points;\n}\n\n// Package custom mouse event.\nfunction packEventData(el, seriesModel, itemNode) {\n    el.eventData = {\n        componentType: 'series',\n        componentSubType: 'treemap',\n        componentIndex: seriesModel.componentIndex,\n        seriesIndex: seriesModel.componentIndex,\n        seriesName: seriesModel.name,\n        seriesType: 'treemap',\n        selfType: 'breadcrumb', // Distinguish with click event on treemap node.\n        nodeData: {\n            dataIndex: itemNode && itemNode.dataIndex,\n            name: itemNode && itemNode.name\n        },\n        treePathInfo: itemNode && wrapTreePathInfo(itemNode, seriesModel)\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {number} [time=500] Time in ms\n * @param {string} [easing='linear']\n * @param {number} [delay=0]\n * @param {Function} [callback]\n *\n * @example\n *  // Animate position\n *  animation\n *      .createWrap()\n *      .add(el1, {position: [10, 10]})\n *      .add(el2, {shape: {width: 500}, style: {fill: 'red'}}, 400)\n *      .done(function () { // done })\n *      .start('cubicOut');\n */\nfunction createWrap() {\n\n    var storage = [];\n    var elExistsMap = {};\n    var doneCallback;\n\n    return {\n\n        /**\n         * Caution: a el can only be added once, otherwise 'done'\n         * might not be called. This method checks this (by el.id),\n         * suppresses adding and returns false when existing el found.\n         *\n         * @param {modele:zrender/Element} el\n         * @param {Object} target\n         * @param {number} [time=500]\n         * @param {number} [delay=0]\n         * @param {string} [easing='linear']\n         * @return {boolean} Whether adding succeeded.\n         *\n         * @example\n         *     add(el, target, time, delay, easing);\n         *     add(el, target, time, easing);\n         *     add(el, target, time);\n         *     add(el, target);\n         */\n        add: function (el, target, time, delay, easing) {\n            if (isString(delay)) {\n                easing = delay;\n                delay = 0;\n            }\n\n            if (elExistsMap[el.id]) {\n                return false;\n            }\n            elExistsMap[el.id] = 1;\n\n            storage.push(\n                {el: el, target: target, time: time, delay: delay, easing: easing}\n            );\n\n            return true;\n        },\n\n        /**\n         * Only execute when animation finished. Will not execute when any\n         * of 'stop' or 'stopAnimation' called.\n         *\n         * @param {Function} callback\n         */\n        done: function (callback) {\n            doneCallback = callback;\n            return this;\n        },\n\n        /**\n         * Will stop exist animation firstly.\n         */\n        start: function () {\n            var count = storage.length;\n\n            for (var i = 0, len = storage.length; i < len; i++) {\n                var item = storage[i];\n                item.el.animateTo(item.target, item.time, item.delay, item.easing, done);\n            }\n\n            return this;\n\n            function done() {\n                count--;\n                if (!count) {\n                    storage.length = 0;\n                    elExistsMap = {};\n                    doneCallback && doneCallback();\n                }\n            }\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$1 = bind;\nvar Group$2 = Group;\nvar Rect$1 = Rect;\nvar each$8 = each$1;\n\nvar DRAG_THRESHOLD = 3;\nvar PATH_LABEL_NOAMAL = ['label'];\nvar PATH_LABEL_EMPHASIS = ['emphasis', 'label'];\nvar PATH_UPPERLABEL_NORMAL = ['upperLabel'];\nvar PATH_UPPERLABEL_EMPHASIS = ['emphasis', 'upperLabel'];\nvar Z_BASE = 10; // Should bigger than every z.\nvar Z_BG = 1;\nvar Z_CONTENT = 2;\n\nvar getItemStyleEmphasis = makeStyleMapper([\n    ['fill', 'color'],\n    // `borderColor` and `borderWidth` has been occupied,\n    // so use `stroke` to indicate the stroke of the rect.\n    ['stroke', 'strokeColor'],\n    ['lineWidth', 'strokeWidth'],\n    ['shadowBlur'],\n    ['shadowOffsetX'],\n    ['shadowOffsetY'],\n    ['shadowColor']\n]);\nvar getItemStyleNormal = function (model) {\n    // Normal style props should include emphasis style props.\n    var itemStyle = getItemStyleEmphasis(model);\n    // Clear styles set by emphasis.\n    itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;\n    return itemStyle;\n};\n\nextendChartView({\n\n    type: 'treemap',\n\n    /**\n     * @override\n     */\n    init: function (o, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this._containerGroup;\n\n        /**\n         * @private\n         * @type {Object.<string, Array.<module:zrender/container/Group>>}\n         */\n        this._storage = createStorage();\n\n        /**\n         * @private\n         * @type {module:echarts/data/Tree}\n         */\n        this._oldTree;\n\n        /**\n         * @private\n         * @type {module:echarts/chart/treemap/Breadcrumb}\n         */\n        this._breadcrumb;\n\n        /**\n         * @private\n         * @type {module:echarts/component/helper/RoamController}\n         */\n        this._controller;\n\n        /**\n         * 'ready', 'animating'\n         * @private\n         */\n        this._state = 'ready';\n    },\n\n    /**\n     * @override\n     */\n    render: function (seriesModel, ecModel, api, payload) {\n\n        var models = ecModel.findComponents({\n            mainType: 'series', subType: 'treemap', query: payload\n        });\n        if (indexOf(models, seriesModel) < 0) {\n            return;\n        }\n\n        this.seriesModel = seriesModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        var types = ['treemapZoomToNode', 'treemapRootToNode'];\n        var targetInfo = retrieveTargetInfo(payload, types, seriesModel);\n        var payloadType = payload && payload.type;\n        var layoutInfo = seriesModel.layoutInfo;\n        var isInit = !this._oldTree;\n        var thisStorage = this._storage;\n\n        // Mark new root when action is treemapRootToNode.\n        var reRoot = (payloadType === 'treemapRootToNode' && targetInfo && thisStorage)\n            ? {\n                rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()],\n                direction: payload.direction\n            }\n            : null;\n\n        var containerGroup = this._giveContainerGroup(layoutInfo);\n\n        var renderResult = this._doRender(containerGroup, seriesModel, reRoot);\n        (\n            !isInit && (\n                !payloadType\n                || payloadType === 'treemapZoomToNode'\n                || payloadType === 'treemapRootToNode'\n            )\n        )\n            ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot)\n            : renderResult.renderFinally();\n\n        this._resetController(api);\n\n        this._renderBreadcrumb(seriesModel, api, targetInfo);\n    },\n\n    /**\n     * @private\n     */\n    _giveContainerGroup: function (layoutInfo) {\n        var containerGroup = this._containerGroup;\n        if (!containerGroup) {\n            // FIXME\n            // 加一层containerGroup是为了clip，但是现在clip功能并没有实现。\n            containerGroup = this._containerGroup = new Group$2();\n            this._initEvents(containerGroup);\n            this.group.add(containerGroup);\n        }\n        containerGroup.attr('position', [layoutInfo.x, layoutInfo.y]);\n\n        return containerGroup;\n    },\n\n    /**\n     * @private\n     */\n    _doRender: function (containerGroup, seriesModel, reRoot) {\n        var thisTree = seriesModel.getData().tree;\n        var oldTree = this._oldTree;\n\n        // Clear last shape records.\n        var lastsForAnimation = createStorage();\n        var thisStorage = createStorage();\n        var oldStorage = this._storage;\n        var willInvisibleEls = [];\n        var doRenderNode = curry(\n            renderNode, seriesModel,\n            thisStorage, oldStorage, reRoot,\n            lastsForAnimation, willInvisibleEls\n        );\n\n        // Notice: when thisTree and oldTree are the same tree (see list.cloneShallow),\n        // the oldTree is actually losted, so we can not find all of the old graphic\n        // elements from tree. So we use this stragegy: make element storage, move\n        // from old storage to new storage, clear old storage.\n\n        dualTravel(\n            thisTree.root ? [thisTree.root] : [],\n            (oldTree && oldTree.root) ? [oldTree.root] : [],\n            containerGroup,\n            thisTree === oldTree || !oldTree,\n            0\n        );\n\n        // Process all removing.\n        var willDeleteEls = clearStorage(oldStorage);\n\n        this._oldTree = thisTree;\n        this._storage = thisStorage;\n\n        return {\n            lastsForAnimation: lastsForAnimation,\n            willDeleteEls: willDeleteEls,\n            renderFinally: renderFinally\n        };\n\n        function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, depth) {\n            // When 'render' is triggered by action,\n            // 'this' and 'old' may be the same tree,\n            // we use rawIndex in that case.\n            if (sameTree) {\n                oldViewChildren = thisViewChildren;\n                each$8(thisViewChildren, function (child, index) {\n                    !child.isRemoved() && processNode(index, index);\n                });\n            }\n            // Diff hierarchically (diff only in each subtree, but not whole).\n            // because, consistency of view is important.\n            else {\n                (new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey))\n                    .add(processNode)\n                    .update(processNode)\n                    .remove(curry(processNode, null))\n                    .execute();\n            }\n\n            function getKey(node) {\n                // Identify by name or raw index.\n                return node.getId();\n            }\n\n            function processNode(newIndex, oldIndex) {\n                var thisNode = newIndex != null ? thisViewChildren[newIndex] : null;\n                var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null;\n\n                var group = doRenderNode(thisNode, oldNode, parentGroup, depth);\n\n                group && dualTravel(\n                    thisNode && thisNode.viewChildren || [],\n                    oldNode && oldNode.viewChildren || [],\n                    group,\n                    sameTree,\n                    depth + 1\n                );\n            }\n        }\n\n        function clearStorage(storage) {\n            var willDeleteEls = createStorage();\n            storage && each$8(storage, function (store, storageName) {\n                var delEls = willDeleteEls[storageName];\n                each$8(store, function (el) {\n                    el && (delEls.push(el), el.__tmWillDelete = 1);\n                });\n            });\n            return willDeleteEls;\n        }\n\n        function renderFinally() {\n            each$8(willDeleteEls, function (els) {\n                each$8(els, function (el) {\n                    el.parent && el.parent.remove(el);\n                });\n            });\n            each$8(willInvisibleEls, function (el) {\n                el.invisible = true;\n                // Setting invisible is for optimizing, so no need to set dirty,\n                // just mark as invisible.\n                el.dirty();\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _doAnimation: function (containerGroup, renderResult, seriesModel, reRoot) {\n        if (!seriesModel.get('animation')) {\n            return;\n        }\n\n        var duration = seriesModel.get('animationDurationUpdate');\n        var easing = seriesModel.get('animationEasing');\n        var animationWrap = createWrap();\n\n        // Make delete animations.\n        each$8(renderResult.willDeleteEls, function (store, storageName) {\n            each$8(store, function (el, rawIndex) {\n                if (el.invisible) {\n                    return;\n                }\n\n                var parent = el.parent; // Always has parent, and parent is nodeGroup.\n                var target;\n\n                if (reRoot && reRoot.direction === 'drillDown') {\n                    target = parent === reRoot.rootNodeGroup\n                        // This is the content element of view root.\n                        // Only `content` will enter this branch, because\n                        // `background` and `nodeGroup` will not be deleted.\n                        ? {\n                            shape: {\n                                x: 0,\n                                y: 0,\n                                width: parent.__tmNodeWidth,\n                                height: parent.__tmNodeHeight\n                            },\n                            style: {\n                                opacity: 0\n                            }\n                        }\n                        // Others.\n                        : {style: {opacity: 0}};\n                }\n                else {\n                    var targetX = 0;\n                    var targetY = 0;\n\n                    if (!parent.__tmWillDelete) {\n                        // Let node animate to right-bottom corner, cooperating with fadeout,\n                        // which is appropriate for user understanding.\n                        // Divided by 2 for reRoot rolling up effect.\n                        targetX = parent.__tmNodeWidth / 2;\n                        targetY = parent.__tmNodeHeight / 2;\n                    }\n\n                    target = storageName === 'nodeGroup'\n                        ? {position: [targetX, targetY], style: {opacity: 0}}\n                        : {\n                            shape: {x: targetX, y: targetY, width: 0, height: 0},\n                            style: {opacity: 0}\n                        };\n                }\n\n                target && animationWrap.add(el, target, duration, easing);\n            });\n        });\n\n        // Make other animations\n        each$8(this._storage, function (store, storageName) {\n            each$8(store, function (el, rawIndex) {\n                var last = renderResult.lastsForAnimation[storageName][rawIndex];\n                var target = {};\n\n                if (!last) {\n                    return;\n                }\n\n                if (storageName === 'nodeGroup') {\n                    if (last.old) {\n                        target.position = el.position.slice();\n                        el.attr('position', last.old);\n                    }\n                }\n                else {\n                    if (last.old) {\n                        target.shape = extend({}, el.shape);\n                        el.setShape(last.old);\n                    }\n\n                    if (last.fadein) {\n                        el.setStyle('opacity', 0);\n                        target.style = {opacity: 1};\n                    }\n                    // When animation is stopped for succedent animation starting,\n                    // el.style.opacity might not be 1\n                    else if (el.style.opacity !== 1) {\n                        target.style = {opacity: 1};\n                    }\n                }\n\n                animationWrap.add(el, target, duration, easing);\n            });\n        }, this);\n\n        this._state = 'animating';\n\n        animationWrap\n            .done(bind$1(function () {\n                this._state = 'ready';\n                renderResult.renderFinally();\n            }, this))\n            .start();\n    },\n\n    /**\n     * @private\n     */\n    _resetController: function (api) {\n        var controller = this._controller;\n\n        // Init controller.\n        if (!controller) {\n            controller = this._controller = new RoamController(api.getZr());\n            controller.enable(this.seriesModel.get('roam'));\n            controller.on('pan', bind$1(this._onPan, this));\n            controller.on('zoom', bind$1(this._onZoom, this));\n        }\n\n        var rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight());\n        controller.setPointerChecker(function (e, x, y) {\n            return rect.contain(x, y);\n        });\n    },\n\n    /**\n     * @private\n     */\n    _clearController: function () {\n        var controller = this._controller;\n        if (controller) {\n            controller.dispose();\n            controller = null;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _onPan: function (e) {\n        if (this._state !== 'animating'\n            && (Math.abs(e.dx) > DRAG_THRESHOLD || Math.abs(e.dy) > DRAG_THRESHOLD)\n        ) {\n            // These param must not be cached.\n            var root = this.seriesModel.getData().tree.root;\n\n            if (!root) {\n                return;\n            }\n\n            var rootLayout = root.getLayout();\n\n            if (!rootLayout) {\n                return;\n            }\n\n            this.api.dispatchAction({\n                type: 'treemapMove',\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                rootRect: {\n                    x: rootLayout.x + e.dx, y: rootLayout.y + e.dy,\n                    width: rootLayout.width, height: rootLayout.height\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _onZoom: function (e) {\n        var mouseX = e.originX;\n        var mouseY = e.originY;\n\n        if (this._state !== 'animating') {\n            // These param must not be cached.\n            var root = this.seriesModel.getData().tree.root;\n\n            if (!root) {\n                return;\n            }\n\n            var rootLayout = root.getLayout();\n\n            if (!rootLayout) {\n                return;\n            }\n\n            var rect = new BoundingRect(\n                rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height\n            );\n            var layoutInfo = this.seriesModel.layoutInfo;\n\n            // Transform mouse coord from global to containerGroup.\n            mouseX -= layoutInfo.x;\n            mouseY -= layoutInfo.y;\n\n            // Scale root bounding rect.\n            var m = create$1();\n            translate(m, m, [-mouseX, -mouseY]);\n            scale$1(m, m, [e.scale, e.scale]);\n            translate(m, m, [mouseX, mouseY]);\n\n            rect.applyTransform(m);\n\n            this.api.dispatchAction({\n                type: 'treemapRender',\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                rootRect: {\n                    x: rect.x, y: rect.y,\n                    width: rect.width, height: rect.height\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _initEvents: function (containerGroup) {\n        containerGroup.on('click', function (e) {\n            if (this._state !== 'ready') {\n                return;\n            }\n\n            var nodeClick = this.seriesModel.get('nodeClick', true);\n\n            if (!nodeClick) {\n                return;\n            }\n\n            var targetInfo = this.findTarget(e.offsetX, e.offsetY);\n\n            if (!targetInfo) {\n                return;\n            }\n\n            var node = targetInfo.node;\n            if (node.getLayout().isLeafRoot) {\n                this._rootToNode(targetInfo);\n            }\n            else {\n                if (nodeClick === 'zoomToNode') {\n                    this._zoomToNode(targetInfo);\n                }\n                else if (nodeClick === 'link') {\n                    var itemModel = node.hostTree.data.getItemModel(node.dataIndex);\n                    var link = itemModel.get('link', true);\n                    var linkTarget = itemModel.get('target', true) || 'blank';\n                    link && window.open(link, linkTarget);\n                }\n            }\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderBreadcrumb: function (seriesModel, api, targetInfo) {\n        if (!targetInfo) {\n            targetInfo = seriesModel.get('leafDepth', true) != null\n                ? {node: seriesModel.getViewRoot()}\n                // FIXME\n                // better way?\n                // Find breadcrumb tail on center of containerGroup.\n                : this.findTarget(api.getWidth() / 2, api.getHeight() / 2);\n\n            if (!targetInfo) {\n                targetInfo = {node: seriesModel.getData().tree.root};\n            }\n        }\n\n        (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group)))\n            .render(seriesModel, api, targetInfo.node, bind$1(onSelect, this));\n\n        function onSelect(node) {\n            if (this._state !== 'animating') {\n                aboveViewRoot(seriesModel.getViewRoot(), node)\n                    ? this._rootToNode({node: node})\n                    : this._zoomToNode({node: node});\n            }\n        }\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearController();\n        this._containerGroup && this._containerGroup.removeAll();\n        this._storage = createStorage();\n        this._state = 'ready';\n        this._breadcrumb && this._breadcrumb.remove();\n    },\n\n    dispose: function () {\n        this._clearController();\n    },\n\n    /**\n     * @private\n     */\n    _zoomToNode: function (targetInfo) {\n        this.api.dispatchAction({\n            type: 'treemapZoomToNode',\n            from: this.uid,\n            seriesId: this.seriesModel.id,\n            targetNode: targetInfo.node\n        });\n    },\n\n    /**\n     * @private\n     */\n    _rootToNode: function (targetInfo) {\n        this.api.dispatchAction({\n            type: 'treemapRootToNode',\n            from: this.uid,\n            seriesId: this.seriesModel.id,\n            targetNode: targetInfo.node\n        });\n    },\n\n    /**\n     * @public\n     * @param {number} x Global coord x.\n     * @param {number} y Global coord y.\n     * @return {Object} info If not found, return undefined;\n     * @return {number} info.node Target node.\n     * @return {number} info.offsetX x refer to target node.\n     * @return {number} info.offsetY y refer to target node.\n     */\n    findTarget: function (x, y) {\n        var targetInfo;\n        var viewRoot = this.seriesModel.getViewRoot();\n\n        viewRoot.eachNode({attr: 'viewChildren', order: 'preorder'}, function (node) {\n            var bgEl = this._storage.background[node.getRawIndex()];\n            // If invisible, there might be no element.\n            if (bgEl) {\n                var point = bgEl.transformCoordToLocal(x, y);\n                var shape = bgEl.shape;\n\n                // For performance consideration, dont use 'getBoundingRect'.\n                if (shape.x <= point[0]\n                    && point[0] <= shape.x + shape.width\n                    && shape.y <= point[1]\n                    && point[1] <= shape.y + shape.height\n                ) {\n                    targetInfo = {node: node, offsetX: point[0], offsetY: point[1]};\n                }\n                else {\n                    return false; // Suppress visit subtree.\n                }\n            }\n        }, this);\n\n        return targetInfo;\n    }\n\n});\n\n/**\n * @inner\n */\nfunction createStorage() {\n    return {nodeGroup: [], background: [], content: []};\n}\n\n/**\n * @inner\n * @return Return undefined means do not travel further.\n */\nfunction renderNode(\n    seriesModel, thisStorage, oldStorage, reRoot,\n    lastsForAnimation, willInvisibleEls,\n    thisNode, oldNode, parentGroup, depth\n) {\n    // Whether under viewRoot.\n    if (!thisNode) {\n        // Deleting nodes will be performed finally. This method just find\n        // element from old storage, or create new element, set them to new\n        // storage, and set styles.\n        return;\n    }\n\n    // -------------------------------------------------------------------\n    // Start of closure variables available in \"Procedures in renderNode\".\n\n    var thisLayout = thisNode.getLayout();\n\n    if (!thisLayout || !thisLayout.isInView) {\n        return;\n    }\n\n    var thisWidth = thisLayout.width;\n    var thisHeight = thisLayout.height;\n    var borderWidth = thisLayout.borderWidth;\n    var thisInvisible = thisLayout.invisible;\n\n    var thisRawIndex = thisNode.getRawIndex();\n    var oldRawIndex = oldNode && oldNode.getRawIndex();\n\n    var thisViewChildren = thisNode.viewChildren;\n    var upperHeight = thisLayout.upperHeight;\n    var isParent = thisViewChildren && thisViewChildren.length;\n    var itemStyleNormalModel = thisNode.getModel('itemStyle');\n    var itemStyleEmphasisModel = thisNode.getModel('emphasis.itemStyle');\n\n    // End of closure ariables available in \"Procedures in renderNode\".\n    // -----------------------------------------------------------------\n\n    // Node group\n    var group = giveGraphic('nodeGroup', Group$2);\n\n    if (!group) {\n        return;\n    }\n\n    parentGroup.add(group);\n    // x,y are not set when el is above view root.\n    group.attr('position', [thisLayout.x || 0, thisLayout.y || 0]);\n    group.__tmNodeWidth = thisWidth;\n    group.__tmNodeHeight = thisHeight;\n\n    if (thisLayout.isAboveViewRoot) {\n        return group;\n    }\n\n    // Background\n    var bg = giveGraphic('background', Rect$1, depth, Z_BG);\n    bg && renderBackground(group, bg, isParent && thisLayout.upperHeight);\n\n    // No children, render content.\n    if (!isParent) {\n        var content = giveGraphic('content', Rect$1, depth, Z_CONTENT);\n        content && renderContent(group, content);\n    }\n\n    return group;\n\n    // ----------------------------\n    // | Procedures in renderNode |\n    // ----------------------------\n\n    function renderBackground(group, bg, useUpperLabel) {\n        // For tooltip.\n        bg.dataIndex = thisNode.dataIndex;\n        bg.seriesIndex = seriesModel.seriesIndex;\n\n        bg.setShape({x: 0, y: 0, width: thisWidth, height: thisHeight});\n        var visualBorderColor = thisNode.getVisual('borderColor', true);\n        var emphasisBorderColor = itemStyleEmphasisModel.get('borderColor');\n\n        updateStyle(bg, function () {\n            var normalStyle = getItemStyleNormal(itemStyleNormalModel);\n            normalStyle.fill = visualBorderColor;\n            var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);\n            emphasisStyle.fill = emphasisBorderColor;\n\n            if (useUpperLabel) {\n                var upperLabelWidth = thisWidth - 2 * borderWidth;\n\n                prepareText(\n                    normalStyle, emphasisStyle, visualBorderColor, upperLabelWidth, upperHeight,\n                    {x: borderWidth, y: 0, width: upperLabelWidth, height: upperHeight}\n                );\n            }\n            // For old bg.\n            else {\n                normalStyle.text = emphasisStyle.text = null;\n            }\n\n            bg.setStyle(normalStyle);\n            setHoverStyle(bg, emphasisStyle);\n        });\n\n        group.add(bg);\n    }\n\n    function renderContent(group, content) {\n        // For tooltip.\n        content.dataIndex = thisNode.dataIndex;\n        content.seriesIndex = seriesModel.seriesIndex;\n\n        var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0);\n        var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0);\n\n        content.culling = true;\n        content.setShape({\n            x: borderWidth,\n            y: borderWidth,\n            width: contentWidth,\n            height: contentHeight\n        });\n\n        var visualColor = thisNode.getVisual('color', true);\n        updateStyle(content, function () {\n            var normalStyle = getItemStyleNormal(itemStyleNormalModel);\n            normalStyle.fill = visualColor;\n            var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);\n\n            prepareText(normalStyle, emphasisStyle, visualColor, contentWidth, contentHeight);\n\n            content.setStyle(normalStyle);\n            setHoverStyle(content, emphasisStyle);\n        });\n\n        group.add(content);\n    }\n\n    function updateStyle(element, cb) {\n        if (!thisInvisible) {\n            // If invisible, do not set visual, otherwise the element will\n            // change immediately before animation. We think it is OK to\n            // remain its origin color when moving out of the view window.\n            cb();\n\n            if (!element.__tmWillVisible) {\n                element.invisible = false;\n            }\n        }\n        else {\n            // Delay invisible setting utill animation finished,\n            // avoid element vanish suddenly before animation.\n            !element.invisible && willInvisibleEls.push(element);\n        }\n    }\n\n    function prepareText(normalStyle, emphasisStyle, visualColor, width, height, upperLabelRect) {\n        var nodeModel = thisNode.getModel();\n        var text = retrieve(\n            seriesModel.getFormattedLabel(\n                thisNode.dataIndex, 'normal', null, null, upperLabelRect ? 'upperLabel' : 'label'\n            ),\n            nodeModel.get('name')\n        );\n        if (!upperLabelRect && thisLayout.isLeafRoot) {\n            var iconChar = seriesModel.get('drillDownIcon', true);\n            text = iconChar ? iconChar + ' ' + text : text;\n        }\n\n        var normalLabelModel = nodeModel.getModel(\n            upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL\n        );\n        var emphasisLabelModel = nodeModel.getModel(\n            upperLabelRect ? PATH_UPPERLABEL_EMPHASIS : PATH_LABEL_EMPHASIS\n        );\n\n        var isShow = normalLabelModel.getShallow('show');\n\n        setLabelStyle(\n            normalStyle, emphasisStyle, normalLabelModel, emphasisLabelModel,\n            {\n                defaultText: isShow ? text : null,\n                autoColor: visualColor,\n                isRectText: true\n            }\n        );\n\n        upperLabelRect && (normalStyle.textRect = clone(upperLabelRect));\n\n        normalStyle.truncate = (isShow && normalLabelModel.get('ellipsis'))\n            ? {\n                outerWidth: width,\n                outerHeight: height,\n                minChar: 2\n            }\n            : null;\n    }\n\n    function giveGraphic(storageName, Ctor, depth, z) {\n        var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex];\n        var lasts = lastsForAnimation[storageName];\n\n        if (element) {\n            // Remove from oldStorage\n            oldStorage[storageName][oldRawIndex] = null;\n            prepareAnimationWhenHasOld(lasts, element, storageName);\n        }\n        // If invisible and no old element, do not create new element (for optimizing).\n        else if (!thisInvisible) {\n            element = new Ctor({z: calculateZ(depth, z)});\n            element.__tmDepth = depth;\n            element.__tmStorageName = storageName;\n            prepareAnimationWhenNoOld(lasts, element, storageName);\n        }\n\n        // Set to thisStorage\n        return (thisStorage[storageName][thisRawIndex] = element);\n    }\n\n    function prepareAnimationWhenHasOld(lasts, element, storageName) {\n        var lastCfg = lasts[thisRawIndex] = {};\n        lastCfg.old = storageName === 'nodeGroup'\n            ? element.position.slice()\n            : extend({}, element.shape);\n    }\n\n    // If a element is new, we need to find the animation start point carefully,\n    // otherwise it will looks strange when 'zoomToNode'.\n    function prepareAnimationWhenNoOld(lasts, element, storageName) {\n        var lastCfg = lasts[thisRawIndex] = {};\n        var parentNode = thisNode.parentNode;\n\n        if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) {\n            var parentOldX = 0;\n            var parentOldY = 0;\n\n            // New nodes appear from right-bottom corner in 'zoomToNode' animation.\n            // For convenience, get old bounding rect from background.\n            var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()];\n            if (!reRoot && parentOldBg && parentOldBg.old) {\n                parentOldX = parentOldBg.old.width;\n                parentOldY = parentOldBg.old.height;\n            }\n\n            // When no parent old shape found, its parent is new too,\n            // so we can just use {x:0, y:0}.\n            lastCfg.old = storageName === 'nodeGroup'\n                ? [0, parentOldY]\n                : {x: parentOldX, y: parentOldY, width: 0, height: 0};\n        }\n\n        // Fade in, user can be aware that these nodes are new.\n        lastCfg.fadein = storageName !== 'nodeGroup';\n    }\n}\n\n// We can not set all backgroud with the same z, Because the behaviour of\n// drill down and roll up differ background creation sequence from tree\n// hierarchy sequence, which cause that lowser background element overlap\n// upper ones. So we calculate z based on depth.\n// Moreover, we try to shrink down z interval to [0, 1] to avoid that\n// treemap with large z overlaps other components.\nfunction calculateZ(depth, zInLevel) {\n    var zb = depth * Z_BASE + zInLevel;\n    return (zb - 1) / zb;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Treemap action\n */\n\nvar noop$1 = function () {};\n\nvar actionTypes = [\n    'treemapZoomToNode',\n    'treemapRender',\n    'treemapMove'\n];\n\nfor (var i$2 = 0; i$2 < actionTypes.length; i$2++) {\n    registerAction({type: actionTypes[i$2], update: 'updateView'}, noop$1);\n}\n\nregisterAction(\n    {type: 'treemapRootToNode', update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'treemap', query: payload},\n            handleRootToNode\n        );\n\n        function handleRootToNode(model, index) {\n            var types = ['treemapZoomToNode', 'treemapRootToNode'];\n            var targetInfo = retrieveTargetInfo(payload, types, model);\n\n            if (targetInfo) {\n                var originViewRoot = model.getViewRoot();\n                if (originViewRoot) {\n                    payload.direction = aboveViewRoot(originViewRoot, targetInfo.node)\n                        ? 'rollUp' : 'drillDown';\n                }\n                model.resetViewRoot(targetInfo.node);\n            }\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$9 = each$1;\nvar isObject$5 = isObject$1;\n\nvar CATEGORY_DEFAULT_VISUAL_INDEX = -1;\n\n/**\n * @param {Object} option\n * @param {string} [option.type] See visualHandlers.\n * @param {string} [option.mappingMethod] 'linear' or 'piecewise' or 'category' or 'fixed'\n * @param {Array.<number>=} [option.dataExtent] [minExtent, maxExtent],\n *                                              required when mappingMethod is 'linear'\n * @param {Array.<Object>=} [option.pieceList] [\n *                                             {value: someValue},\n *                                             {interval: [min1, max1], visual: {...}},\n *                                             {interval: [min2, max2]}\n *                                             ],\n *                                            required when mappingMethod is 'piecewise'.\n *                                            Visual for only each piece can be specified.\n * @param {Array.<string|Object>=} [option.categories] ['cate1', 'cate2']\n *                                            required when mappingMethod is 'category'.\n *                                            If no option.categories, categories is set\n *                                            as [0, 1, 2, ...].\n * @param {boolean} [option.loop=false] Whether loop mapping when mappingMethod is 'category'.\n * @param {(Array|Object|*)} [option.visual]  Visual data.\n *                                            when mappingMethod is 'category',\n *                                            visual data can be array or object\n *                                            (like: {cate1: '#222', none: '#fff'})\n *                                            or primary types (which represents\n *                                            defualt category visual), otherwise visual\n *                                            can be array or primary (which will be\n *                                            normalized to array).\n *\n */\nvar VisualMapping = function (option) {\n    var mappingMethod = option.mappingMethod;\n    var visualType = option.type;\n\n    /**\n     * @readOnly\n     * @type {Object}\n     */\n    var thisOption = this.option = clone(option);\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    this.type = visualType;\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    this.mappingMethod = mappingMethod;\n\n    /**\n     * @private\n     * @type {Function}\n     */\n    this._normalizeData = normalizers[mappingMethod];\n\n    var visualHandler = visualHandlers[visualType];\n\n    /**\n     * @public\n     * @type {Function}\n     */\n    this.applyVisual = visualHandler.applyVisual;\n\n    /**\n     * @public\n     * @type {Function}\n     */\n    this.getColorMapper = visualHandler.getColorMapper;\n\n    /**\n     * @private\n     * @type {Function}\n     */\n    this._doMap = visualHandler._doMap[mappingMethod];\n\n    if (mappingMethod === 'piecewise') {\n        normalizeVisualRange(thisOption);\n        preprocessForPiecewise(thisOption);\n    }\n    else if (mappingMethod === 'category') {\n        thisOption.categories\n            ? preprocessForSpecifiedCategory(thisOption)\n            // categories is ordinal when thisOption.categories not specified,\n            // which need no more preprocess except normalize visual.\n            : normalizeVisualRange(thisOption, true);\n    }\n    else { // mappingMethod === 'linear' or 'fixed'\n        assert$1(mappingMethod !== 'linear' || thisOption.dataExtent);\n        normalizeVisualRange(thisOption);\n    }\n};\n\nVisualMapping.prototype = {\n\n    constructor: VisualMapping,\n\n    mapValueToVisual: function (value) {\n        var normalized = this._normalizeData(value);\n        return this._doMap(normalized, value);\n    },\n\n    getNormalizer: function () {\n        return bind(this._normalizeData, this);\n    }\n};\n\nvar visualHandlers = VisualMapping.visualHandlers = {\n\n    color: {\n\n        applyVisual: makeApplyVisual('color'),\n\n        /**\n         * Create a mapper function\n         * @return {Function}\n         */\n        getColorMapper: function () {\n            var thisOption = this.option;\n\n            return bind(\n                thisOption.mappingMethod === 'category'\n                    ? function (value, isNormalized) {\n                        !isNormalized && (value = this._normalizeData(value));\n                        return doMapCategory.call(this, value);\n                    }\n                    : function (value, isNormalized, out) {\n                        // If output rgb array\n                        // which will be much faster and useful in pixel manipulation\n                        var returnRGBArray = !!out;\n                        !isNormalized && (value = this._normalizeData(value));\n                        out = fastLerp(value, thisOption.parsedVisual, out);\n                        return returnRGBArray ? out : stringify(out, 'rgba');\n                    },\n                this\n            );\n        },\n\n        _doMap: {\n            linear: function (normalized) {\n                return stringify(\n                    fastLerp(normalized, this.option.parsedVisual),\n                    'rgba'\n                );\n            },\n            category: doMapCategory,\n            piecewise: function (normalized, value) {\n                var result = getSpecifiedVisual.call(this, value);\n                if (result == null) {\n                    result = stringify(\n                        fastLerp(normalized, this.option.parsedVisual),\n                        'rgba'\n                    );\n                }\n                return result;\n            },\n            fixed: doMapFixed\n        }\n    },\n\n    colorHue: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, value);\n    }),\n\n    colorSaturation: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, null, value);\n    }),\n\n    colorLightness: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, null, null, value);\n    }),\n\n    colorAlpha: makePartialColorVisualHandler(function (color, value) {\n        return modifyAlpha(color, value);\n    }),\n\n    opacity: {\n        applyVisual: makeApplyVisual('opacity'),\n        _doMap: makeDoMap([0, 1])\n    },\n\n    liftZ: {\n        applyVisual: makeApplyVisual('liftZ'),\n        _doMap: {\n            linear: doMapFixed,\n            category: doMapFixed,\n            piecewise: doMapFixed,\n            fixed: doMapFixed\n        }\n    },\n\n    symbol: {\n        applyVisual: function (value, getter, setter) {\n            var symbolCfg = this.mapValueToVisual(value);\n            if (isString(symbolCfg)) {\n                setter('symbol', symbolCfg);\n            }\n            else if (isObject$5(symbolCfg)) {\n                for (var name in symbolCfg) {\n                    if (symbolCfg.hasOwnProperty(name)) {\n                        setter(name, symbolCfg[name]);\n                    }\n                }\n            }\n        },\n        _doMap: {\n            linear: doMapToArray,\n            category: doMapCategory,\n            piecewise: function (normalized, value) {\n                var result = getSpecifiedVisual.call(this, value);\n                if (result == null) {\n                    result = doMapToArray.call(this, normalized);\n                }\n                return result;\n            },\n            fixed: doMapFixed\n        }\n    },\n\n    symbolSize: {\n        applyVisual: makeApplyVisual('symbolSize'),\n        _doMap: makeDoMap([0, 1])\n    }\n};\n\n\nfunction preprocessForPiecewise(thisOption) {\n    var pieceList = thisOption.pieceList;\n    thisOption.hasSpecialVisual = false;\n\n    each$1(pieceList, function (piece, index) {\n        piece.originIndex = index;\n        // piece.visual is \"result visual value\" but not\n        // a visual range, so it does not need to be normalized.\n        if (piece.visual != null) {\n            thisOption.hasSpecialVisual = true;\n        }\n    });\n}\n\nfunction preprocessForSpecifiedCategory(thisOption) {\n    // Hash categories.\n    var categories = thisOption.categories;\n    var visual = thisOption.visual;\n\n    var categoryMap = thisOption.categoryMap = {};\n    each$9(categories, function (cate, index) {\n        categoryMap[cate] = index;\n    });\n\n    // Process visual map input.\n    if (!isArray(visual)) {\n        var visualArr = [];\n\n        if (isObject$1(visual)) {\n            each$9(visual, function (v, cate) {\n                var index = categoryMap[cate];\n                visualArr[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v;\n            });\n        }\n        else { // Is primary type, represents default visual.\n            visualArr[CATEGORY_DEFAULT_VISUAL_INDEX] = visual;\n        }\n\n        visual = setVisualToOption(thisOption, visualArr);\n    }\n\n    // Remove categories that has no visual,\n    // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX.\n    for (var i = categories.length - 1; i >= 0; i--) {\n        if (visual[i] == null) {\n            delete categoryMap[categories[i]];\n            categories.pop();\n        }\n    }\n}\n\nfunction normalizeVisualRange(thisOption, isCategory) {\n    var visual = thisOption.visual;\n    var visualArr = [];\n\n    if (isObject$1(visual)) {\n        each$9(visual, function (v) {\n            visualArr.push(v);\n        });\n    }\n    else if (visual != null) {\n        visualArr.push(visual);\n    }\n\n    var doNotNeedPair = {color: 1, symbol: 1};\n\n    if (!isCategory\n        && visualArr.length === 1\n        && !doNotNeedPair.hasOwnProperty(thisOption.type)\n    ) {\n        // Do not care visualArr.length === 0, which is illegal.\n        visualArr[1] = visualArr[0];\n    }\n\n    setVisualToOption(thisOption, visualArr);\n}\n\nfunction makePartialColorVisualHandler(applyValue) {\n    return {\n        applyVisual: function (value, getter, setter) {\n            value = this.mapValueToVisual(value);\n            // Must not be array value\n            setter('color', applyValue(getter('color'), value));\n        },\n        _doMap: makeDoMap([0, 1])\n    };\n}\n\nfunction doMapToArray(normalized) {\n    var visual = this.option.visual;\n    return visual[\n        Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))\n    ] || {};\n}\n\nfunction makeApplyVisual(visualType) {\n    return function (value, getter, setter) {\n        setter(visualType, this.mapValueToVisual(value));\n    };\n}\n\nfunction doMapCategory(normalized) {\n    var visual = this.option.visual;\n    return visual[\n        (this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX)\n            ? normalized % visual.length\n            : normalized\n    ];\n}\n\nfunction doMapFixed() {\n    return this.option.visual[0];\n}\n\nfunction makeDoMap(sourceExtent) {\n    return {\n        linear: function (normalized) {\n            return linearMap(normalized, sourceExtent, this.option.visual, true);\n        },\n        category: doMapCategory,\n        piecewise: function (normalized, value) {\n            var result = getSpecifiedVisual.call(this, value);\n            if (result == null) {\n                result = linearMap(normalized, sourceExtent, this.option.visual, true);\n            }\n            return result;\n        },\n        fixed: doMapFixed\n    };\n}\n\nfunction getSpecifiedVisual(value) {\n    var thisOption = this.option;\n    var pieceList = thisOption.pieceList;\n    if (thisOption.hasSpecialVisual) {\n        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);\n        var piece = pieceList[pieceIndex];\n        if (piece && piece.visual) {\n            return piece.visual[this.type];\n        }\n    }\n}\n\nfunction setVisualToOption(thisOption, visualArr) {\n    thisOption.visual = visualArr;\n    if (thisOption.type === 'color') {\n        thisOption.parsedVisual = map(visualArr, function (item) {\n            return parse(item);\n        });\n    }\n    return visualArr;\n}\n\n\n/**\n * Normalizers by mapping methods.\n */\nvar normalizers = {\n\n    linear: function (value) {\n        return linearMap(value, this.option.dataExtent, [0, 1], true);\n    },\n\n    piecewise: function (value) {\n        var pieceList = this.option.pieceList;\n        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true);\n        if (pieceIndex != null) {\n            return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true);\n        }\n    },\n\n    category: function (value) {\n        var index = this.option.categories\n            ? this.option.categoryMap[value]\n            : value; // ordinal\n        return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;\n    },\n\n    fixed: noop\n};\n\n\n\n/**\n * List available visual types.\n *\n * @public\n * @return {Array.<string>}\n */\nVisualMapping.listVisualTypes = function () {\n    var visualTypes = [];\n    each$1(visualHandlers, function (handler, key) {\n        visualTypes.push(key);\n    });\n    return visualTypes;\n};\n\n/**\n * @public\n */\nVisualMapping.addVisualHandler = function (name, handler) {\n    visualHandlers[name] = handler;\n};\n\n/**\n * @public\n */\nVisualMapping.isValidType = function (visualType) {\n    return visualHandlers.hasOwnProperty(visualType);\n};\n\n/**\n * Convinent method.\n * Visual can be Object or Array or primary type.\n *\n * @public\n */\nVisualMapping.eachVisual = function (visual, callback, context) {\n    if (isObject$1(visual)) {\n        each$1(visual, callback, context);\n    }\n    else {\n        callback.call(context, visual);\n    }\n};\n\nVisualMapping.mapVisual = function (visual, callback, context) {\n    var isPrimary;\n    var newVisual = isArray(visual)\n        ? []\n        : isObject$1(visual)\n        ? {}\n        : (isPrimary = true, null);\n\n    VisualMapping.eachVisual(visual, function (v, key) {\n        var newVal = callback.call(context, v, key);\n        isPrimary ? (newVisual = newVal) : (newVisual[key] = newVal);\n    });\n    return newVisual;\n};\n\n/**\n * @public\n * @param {Object} obj\n * @return {Object} new object containers visual values.\n *                 If no visuals, return null.\n */\nVisualMapping.retrieveVisuals = function (obj) {\n    var ret = {};\n    var hasVisual;\n\n    obj && each$9(visualHandlers, function (h, visualType) {\n        if (obj.hasOwnProperty(visualType)) {\n            ret[visualType] = obj[visualType];\n            hasVisual = true;\n        }\n    });\n\n    return hasVisual ? ret : null;\n};\n\n/**\n * Give order to visual types, considering colorSaturation, colorAlpha depends on color.\n *\n * @public\n * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}\n *                                     IF Array, like: ['color', 'symbol', 'colorSaturation']\n * @return {Array.<string>} Sorted visual types.\n */\nVisualMapping.prepareVisualTypes = function (visualTypes) {\n    if (isObject$5(visualTypes)) {\n        var types = [];\n        each$9(visualTypes, function (item, type) {\n            types.push(type);\n        });\n        visualTypes = types;\n    }\n    else if (isArray(visualTypes)) {\n        visualTypes = visualTypes.slice();\n    }\n    else {\n        return [];\n    }\n\n    visualTypes.sort(function (type1, type2) {\n        // color should be front of colorSaturation, colorAlpha, ...\n        // symbol and symbolSize do not matter.\n        return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0)\n            ? 1 : -1;\n    });\n\n    return visualTypes;\n};\n\n/**\n * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.\n * Other visuals are only depends on themself.\n *\n * @public\n * @param {string} visualType1\n * @param {string} visualType2\n * @return {boolean}\n */\nVisualMapping.dependsOn = function (visualType1, visualType2) {\n    return visualType2 === 'color'\n        ? !!(visualType1 && visualType1.indexOf(visualType2) === 0)\n        : visualType1 === visualType2;\n};\n\n/**\n * @param {number} value\n * @param {Array.<Object>} pieceList [{value: ..., interval: [min, max]}, ...]\n *                         Always from small to big.\n * @param {boolean} [findClosestWhenOutside=false]\n * @return {number} index\n */\nVisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) {\n    var possibleI;\n    var abs = Infinity;\n\n    // value has the higher priority.\n    for (var i = 0, len = pieceList.length; i < len; i++) {\n        var pieceValue = pieceList[i].value;\n        if (pieceValue != null) {\n            if (pieceValue === value\n                // FIXME\n                // It is supposed to compare value according to value type of dimension,\n                // but currently value type can exactly be string or number.\n                // Compromise for numeric-like string (like '12'), especially\n                // in the case that visualMap.categories is ['22', '33'].\n                || (typeof pieceValue === 'string' && pieceValue === value + '')\n            ) {\n                return i;\n            }\n            findClosestWhenOutside && updatePossible(pieceValue, i);\n        }\n    }\n\n    for (var i = 0, len = pieceList.length; i < len; i++) {\n        var piece = pieceList[i];\n        var interval = piece.interval;\n        var close = piece.close;\n\n        if (interval) {\n            if (interval[0] === -Infinity) {\n                if (littleThan(close[1], value, interval[1])) {\n                    return i;\n                }\n            }\n            else if (interval[1] === Infinity) {\n                if (littleThan(close[0], interval[0], value)) {\n                    return i;\n                }\n            }\n            else if (\n                littleThan(close[0], interval[0], value)\n                && littleThan(close[1], value, interval[1])\n            ) {\n                return i;\n            }\n            findClosestWhenOutside && updatePossible(interval[0], i);\n            findClosestWhenOutside && updatePossible(interval[1], i);\n        }\n    }\n\n    if (findClosestWhenOutside) {\n        return value === Infinity\n            ? pieceList.length - 1\n            : value === -Infinity\n            ? 0\n            : possibleI;\n    }\n\n    function updatePossible(val, index) {\n        var newAbs = Math.abs(val - value);\n        if (newAbs < abs) {\n            abs = newAbs;\n            possibleI = index;\n        }\n    }\n\n};\n\nfunction littleThan(close, a, b) {\n    return close ? a <= b : a < b;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar isArray$2 = isArray;\n\nvar ITEM_STYLE_NORMAL = 'itemStyle';\n\nvar treemapVisual = {\n    seriesType: 'treemap',\n    reset: function (seriesModel, ecModel, api, payload) {\n        var tree = seriesModel.getData().tree;\n        var root = tree.root;\n        var seriesItemStyleModel = seriesModel.getModel(ITEM_STYLE_NORMAL);\n\n        if (root.isRemoved()) {\n            return;\n        }\n\n        var levelItemStyles = map(tree.levelModels, function (levelModel) {\n            return levelModel ? levelModel.get(ITEM_STYLE_NORMAL) : null;\n        });\n\n        travelTree(\n            root, // Visual should calculate from tree root but not view root.\n            {},\n            levelItemStyles,\n            seriesItemStyleModel,\n            seriesModel.getViewRoot().getAncestors(),\n            seriesModel\n        );\n    }\n};\n\nfunction travelTree(\n    node, designatedVisual, levelItemStyles, seriesItemStyleModel,\n    viewRootAncestors, seriesModel\n) {\n    var nodeModel = node.getModel();\n    var nodeLayout = node.getLayout();\n\n    // Optimize\n    if (!nodeLayout || nodeLayout.invisible || !nodeLayout.isInView) {\n        return;\n    }\n\n    var nodeItemStyleModel = node.getModel(ITEM_STYLE_NORMAL);\n    var levelItemStyle = levelItemStyles[node.depth];\n    var visuals = buildVisuals(\n        nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel\n    );\n\n    // calculate border color\n    var borderColor = nodeItemStyleModel.get('borderColor');\n    var borderColorSaturation = nodeItemStyleModel.get('borderColorSaturation');\n    var thisNodeColor;\n    if (borderColorSaturation != null) {\n        // For performance, do not always execute 'calculateColor'.\n        thisNodeColor = calculateColor(visuals, node);\n        borderColor = calculateBorderColor(borderColorSaturation, thisNodeColor);\n    }\n    node.setVisual('borderColor', borderColor);\n\n    var viewChildren = node.viewChildren;\n    if (!viewChildren || !viewChildren.length) {\n        thisNodeColor = calculateColor(visuals, node);\n        // Apply visual to this node.\n        node.setVisual('color', thisNodeColor);\n    }\n    else {\n        var mapping = buildVisualMapping(\n            node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren\n        );\n\n        // Designate visual to children.\n        each$1(viewChildren, function (child, index) {\n            // If higher than viewRoot, only ancestors of viewRoot is needed to visit.\n            if (child.depth >= viewRootAncestors.length\n                || child === viewRootAncestors[child.depth]\n            ) {\n                var childVisual = mapVisual$1(\n                    nodeModel, visuals, child, index, mapping, seriesModel\n                );\n                travelTree(\n                    child, childVisual, levelItemStyles, seriesItemStyleModel,\n                    viewRootAncestors, seriesModel\n                );\n            }\n        });\n    }\n}\n\nfunction buildVisuals(\n    nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel\n) {\n    var visuals = extend({}, designatedVisual);\n\n    each$1(['color', 'colorAlpha', 'colorSaturation'], function (visualName) {\n        // Priority: thisNode > thisLevel > parentNodeDesignated > seriesModel\n        var val = nodeItemStyleModel.get(visualName, true); // Ignore parent\n        val == null && levelItemStyle && (val = levelItemStyle[visualName]);\n        val == null && (val = designatedVisual[visualName]);\n        val == null && (val = seriesItemStyleModel.get(visualName));\n\n        val != null && (visuals[visualName] = val);\n    });\n\n    return visuals;\n}\n\nfunction calculateColor(visuals) {\n    var color = getValueVisualDefine(visuals, 'color');\n\n    if (color) {\n        var colorAlpha = getValueVisualDefine(visuals, 'colorAlpha');\n        var colorSaturation = getValueVisualDefine(visuals, 'colorSaturation');\n        if (colorSaturation) {\n            color = modifyHSL(color, null, null, colorSaturation);\n        }\n        if (colorAlpha) {\n            color = modifyAlpha(color, colorAlpha);\n        }\n\n        return color;\n    }\n}\n\nfunction calculateBorderColor(borderColorSaturation, thisNodeColor) {\n    return thisNodeColor != null\n            ? modifyHSL(thisNodeColor, null, null, borderColorSaturation)\n            : null;\n}\n\nfunction getValueVisualDefine(visuals, name) {\n    var value = visuals[name];\n    if (value != null && value !== 'none') {\n        return value;\n    }\n}\n\nfunction buildVisualMapping(\n    node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren\n) {\n    if (!viewChildren || !viewChildren.length) {\n        return;\n    }\n\n    var rangeVisual = getRangeVisual(nodeModel, 'color')\n        || (\n            visuals.color != null\n            && visuals.color !== 'none'\n            && (\n                getRangeVisual(nodeModel, 'colorAlpha')\n                || getRangeVisual(nodeModel, 'colorSaturation')\n            )\n        );\n\n    if (!rangeVisual) {\n        return;\n    }\n\n    var visualMin = nodeModel.get('visualMin');\n    var visualMax = nodeModel.get('visualMax');\n    var dataExtent = nodeLayout.dataExtent.slice();\n    visualMin != null && visualMin < dataExtent[0] && (dataExtent[0] = visualMin);\n    visualMax != null && visualMax > dataExtent[1] && (dataExtent[1] = visualMax);\n\n    var colorMappingBy = nodeModel.get('colorMappingBy');\n    var opt = {\n        type: rangeVisual.name,\n        dataExtent: dataExtent,\n        visual: rangeVisual.range\n    };\n    if (opt.type === 'color'\n        && (colorMappingBy === 'index' || colorMappingBy === 'id')\n    ) {\n        opt.mappingMethod = 'category';\n        opt.loop = true;\n        // categories is ordinal, so do not set opt.categories.\n    }\n    else {\n        opt.mappingMethod = 'linear';\n    }\n\n    var mapping = new VisualMapping(opt);\n    mapping.__drColorMappingBy = colorMappingBy;\n\n    return mapping;\n}\n\n// Notice: If we dont have the attribute 'colorRange', but only use\n// attribute 'color' to represent both concepts of 'colorRange' and 'color',\n// (It means 'colorRange' when 'color' is Array, means 'color' when not array),\n// this problem will be encountered:\n// If a level-1 node dont have children, and its siblings has children,\n// and colorRange is set on level-1, then the node can not be colored.\n// So we separate 'colorRange' and 'color' to different attributes.\nfunction getRangeVisual(nodeModel, name) {\n    // 'colorRange', 'colorARange', 'colorSRange'.\n    // If not exsits on this node, fetch from levels and series.\n    var range = nodeModel.get(name);\n    return (isArray$2(range) && range.length) ? {name: name, range: range} : null;\n}\n\nfunction mapVisual$1(nodeModel, visuals, child, index, mapping, seriesModel) {\n    var childVisuals = extend({}, visuals);\n\n    if (mapping) {\n        var mappingType = mapping.type;\n        var colorMappingBy = mappingType === 'color' && mapping.__drColorMappingBy;\n        var value = colorMappingBy === 'index'\n            ? index\n            : colorMappingBy === 'id'\n            ? seriesModel.mapIdToIndex(child.getId())\n            : child.getValue(nodeModel.get('visualDimension'));\n\n        childVisuals[mappingType] = mapping.mapValueToVisual(value);\n    }\n\n    return childVisuals;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* The treemap layout implementation references to the treemap\n* layout of d3.js (d3/src/layout/treemap.js in v3). The use of\n* the source code of this file is also subject to the terms\n* and consitions of its license (BSD-3Clause, see\n* <echarts/src/licenses/LICENSE-d3>).\n*/\n\nvar mathMax$4 = Math.max;\nvar mathMin$4 = Math.min;\nvar retrieveValue = retrieve;\nvar each$10 = each$1;\n\nvar PATH_BORDER_WIDTH = ['itemStyle', 'borderWidth'];\nvar PATH_GAP_WIDTH = ['itemStyle', 'gapWidth'];\nvar PATH_UPPER_LABEL_SHOW = ['upperLabel', 'show'];\nvar PATH_UPPER_LABEL_HEIGHT = ['upperLabel', 'height'];\n\n/**\n * @public\n */\nvar treemapLayout = {\n    seriesType: 'treemap',\n    reset: function (seriesModel, ecModel, api, payload) {\n        // Layout result in each node:\n        // {x, y, width, height, area, borderWidth}\n        var ecWidth = api.getWidth();\n        var ecHeight = api.getHeight();\n        var seriesOption = seriesModel.option;\n\n        var layoutInfo = getLayoutRect(\n            seriesModel.getBoxLayoutParams(),\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        var size = seriesOption.size || []; // Compatible with ec2.\n        var containerWidth = parsePercent$1(\n            retrieveValue(layoutInfo.width, size[0]),\n            ecWidth\n        );\n        var containerHeight = parsePercent$1(\n            retrieveValue(layoutInfo.height, size[1]),\n            ecHeight\n        );\n\n        // Fetch payload info.\n        var payloadType = payload && payload.type;\n        var types = ['treemapZoomToNode', 'treemapRootToNode'];\n        var targetInfo = retrieveTargetInfo(payload, types, seriesModel);\n        var rootRect = (payloadType === 'treemapRender' || payloadType === 'treemapMove')\n            ? payload.rootRect : null;\n        var viewRoot = seriesModel.getViewRoot();\n        var viewAbovePath = getPathToRoot(viewRoot);\n\n        if (payloadType !== 'treemapMove') {\n            var rootSize = payloadType === 'treemapZoomToNode'\n                ? estimateRootSize(\n                    seriesModel, targetInfo, viewRoot, containerWidth, containerHeight\n                )\n                : rootRect\n                ? [rootRect.width, rootRect.height]\n                : [containerWidth, containerHeight];\n\n            var sort = seriesOption.sort;\n            if (sort && sort !== 'asc' && sort !== 'desc') {\n                sort = 'desc';\n            }\n            var options = {\n                squareRatio: seriesOption.squareRatio,\n                sort: sort,\n                leafDepth: seriesOption.leafDepth\n            };\n\n            // layout should be cleared because using updateView but not update.\n            viewRoot.hostTree.clearLayouts();\n\n            // TODO\n            // optimize: if out of view clip, do not layout.\n            // But take care that if do not render node out of view clip,\n            // how to calculate start po\n\n            var viewRootLayout = {\n                x: 0, y: 0,\n                width: rootSize[0], height: rootSize[1],\n                area: rootSize[0] * rootSize[1]\n            };\n            viewRoot.setLayout(viewRootLayout);\n\n            squarify(viewRoot, options, false, 0);\n            // Supplement layout.\n            var viewRootLayout = viewRoot.getLayout();\n            each$10(viewAbovePath, function (node, index) {\n                var childValue = (viewAbovePath[index + 1] || viewRoot).getValue();\n                node.setLayout(extend(\n                    {dataExtent: [childValue, childValue], borderWidth: 0, upperHeight: 0},\n                    viewRootLayout\n                ));\n            });\n        }\n\n        var treeRoot = seriesModel.getData().tree.root;\n\n        treeRoot.setLayout(\n            calculateRootPosition(layoutInfo, rootRect, targetInfo),\n            true\n        );\n\n        seriesModel.setLayoutInfo(layoutInfo);\n\n        // FIXME\n        // 现在没有clip功能，暂时取ec高宽。\n        prunning(\n            treeRoot,\n            // Transform to base element coordinate system.\n            new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight),\n            viewAbovePath,\n            viewRoot,\n            0\n        );\n    }\n};\n\n/**\n * Layout treemap with squarify algorithm.\n * @see https://graphics.ethz.ch/teaching/scivis_common/Literature/squarifiedTreeMaps.pdf\n * The implementation references to the treemap layout of d3.js.\n * See the license statement at the head of this file.\n *\n * @protected\n * @param {module:echarts/data/Tree~TreeNode} node\n * @param {Object} options\n * @param {string} options.sort 'asc' or 'desc'\n * @param {number} options.squareRatio\n * @param {boolean} hideChildren\n * @param {number} depth\n */\nfunction squarify(node, options, hideChildren, depth) {\n    var width;\n    var height;\n\n    if (node.isRemoved()) {\n        return;\n    }\n\n    var thisLayout = node.getLayout();\n    width = thisLayout.width;\n    height = thisLayout.height;\n\n    // Considering border and gap\n    var nodeModel = node.getModel();\n    var borderWidth = nodeModel.get(PATH_BORDER_WIDTH);\n    var halfGapWidth = nodeModel.get(PATH_GAP_WIDTH) / 2;\n    var upperLabelHeight = getUpperLabelHeight(nodeModel);\n    var upperHeight = Math.max(borderWidth, upperLabelHeight);\n    var layoutOffset = borderWidth - halfGapWidth;\n    var layoutOffsetUpper = upperHeight - halfGapWidth;\n    var nodeModel = node.getModel();\n\n    node.setLayout({\n        borderWidth: borderWidth,\n        upperHeight: upperHeight,\n        upperLabelHeight: upperLabelHeight\n    }, true);\n\n    width = mathMax$4(width - 2 * layoutOffset, 0);\n    height = mathMax$4(height - layoutOffset - layoutOffsetUpper, 0);\n\n    var totalArea = width * height;\n    var viewChildren = initChildren(\n        node, nodeModel, totalArea, options, hideChildren, depth\n    );\n\n    if (!viewChildren.length) {\n        return;\n    }\n\n    var rect = {x: layoutOffset, y: layoutOffsetUpper, width: width, height: height};\n    var rowFixedLength = mathMin$4(width, height);\n    var best = Infinity; // the best row score so far\n    var row = [];\n    row.area = 0;\n\n    for (var i = 0, len = viewChildren.length; i < len;) {\n        var child = viewChildren[i];\n\n        row.push(child);\n        row.area += child.getLayout().area;\n        var score = worst(row, rowFixedLength, options.squareRatio);\n\n        // continue with this orientation\n        if (score <= best) {\n            i++;\n            best = score;\n        }\n        // abort, and try a different orientation\n        else {\n            row.area -= row.pop().getLayout().area;\n            position(row, rowFixedLength, rect, halfGapWidth, false);\n            rowFixedLength = mathMin$4(rect.width, rect.height);\n            row.length = row.area = 0;\n            best = Infinity;\n        }\n    }\n\n    if (row.length) {\n        position(row, rowFixedLength, rect, halfGapWidth, true);\n    }\n\n    if (!hideChildren) {\n        var childrenVisibleMin = nodeModel.get('childrenVisibleMin');\n        if (childrenVisibleMin != null && totalArea < childrenVisibleMin) {\n            hideChildren = true;\n        }\n    }\n\n    for (var i = 0, len = viewChildren.length; i < len; i++) {\n        squarify(viewChildren[i], options, hideChildren, depth + 1);\n    }\n}\n\n/**\n * Set area to each child, and calculate data extent for visual coding.\n */\nfunction initChildren(node, nodeModel, totalArea, options, hideChildren, depth) {\n    var viewChildren = node.children || [];\n    var orderBy = options.sort;\n    orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null);\n\n    var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth;\n\n    // leafDepth has higher priority.\n    if (hideChildren && !overLeafDepth) {\n        return (node.viewChildren = []);\n    }\n\n    // Sort children, order by desc.\n    viewChildren = filter(viewChildren, function (child) {\n        return !child.isRemoved();\n    });\n\n    sort$1(viewChildren, orderBy);\n\n    var info = statistic(nodeModel, viewChildren, orderBy);\n\n    if (info.sum === 0) {\n        return (node.viewChildren = []);\n    }\n\n    info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren);\n\n    if (info.sum === 0) {\n        return (node.viewChildren = []);\n    }\n\n    // Set area to each child.\n    for (var i = 0, len = viewChildren.length; i < len; i++) {\n        var area = viewChildren[i].getValue() / info.sum * totalArea;\n        // Do not use setLayout({...}, true), because it is needed to clear last layout.\n        viewChildren[i].setLayout({area: area});\n    }\n\n    if (overLeafDepth) {\n        viewChildren.length && node.setLayout({isLeafRoot: true}, true);\n        viewChildren.length = 0;\n    }\n\n    node.viewChildren = viewChildren;\n    node.setLayout({dataExtent: info.dataExtent}, true);\n\n    return viewChildren;\n}\n\n/**\n * Consider 'visibleMin'. Modify viewChildren and get new sum.\n */\nfunction filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) {\n\n    // visibleMin is not supported yet when no option.sort.\n    if (!orderBy) {\n        return sum;\n    }\n\n    var visibleMin = nodeModel.get('visibleMin');\n    var len = orderedChildren.length;\n    var deletePoint = len;\n\n    // Always travel from little value to big value.\n    for (var i = len - 1; i >= 0; i--) {\n        var value = orderedChildren[\n            orderBy === 'asc' ? len - i - 1 : i\n        ].getValue();\n\n        if (value / sum * totalArea < visibleMin) {\n            deletePoint = i;\n            sum -= value;\n        }\n    }\n\n    orderBy === 'asc'\n        ? orderedChildren.splice(0, len - deletePoint)\n        : orderedChildren.splice(deletePoint, len - deletePoint);\n\n    return sum;\n}\n\n/**\n * Sort\n */\nfunction sort$1(viewChildren, orderBy) {\n    if (orderBy) {\n        viewChildren.sort(function (a, b) {\n            var diff = orderBy === 'asc'\n                ? a.getValue() - b.getValue() : b.getValue() - a.getValue();\n            return diff === 0\n                ? (orderBy === 'asc'\n                    ? a.dataIndex - b.dataIndex : b.dataIndex - a.dataIndex\n                )\n                : diff;\n        });\n    }\n    return viewChildren;\n}\n\n/**\n * Statistic\n */\nfunction statistic(nodeModel, children, orderBy) {\n    // Calculate sum.\n    var sum = 0;\n    for (var i = 0, len = children.length; i < len; i++) {\n        sum += children[i].getValue();\n    }\n\n    // Statistic data extent for latter visual coding.\n    // Notice: data extent should be calculate based on raw children\n    // but not filtered view children, otherwise visual mapping will not\n    // be stable when zoom (where children is filtered by visibleMin).\n\n    var dimension = nodeModel.get('visualDimension');\n    var dataExtent;\n\n    // The same as area dimension.\n    if (!children || !children.length) {\n        dataExtent = [NaN, NaN];\n    }\n    else if (dimension === 'value' && orderBy) {\n        dataExtent = [\n            children[children.length - 1].getValue(),\n            children[0].getValue()\n        ];\n        orderBy === 'asc' && dataExtent.reverse();\n    }\n    // Other dimension.\n    else {\n        var dataExtent = [Infinity, -Infinity];\n        each$10(children, function (child) {\n            var value = child.getValue(dimension);\n            value < dataExtent[0] && (dataExtent[0] = value);\n            value > dataExtent[1] && (dataExtent[1] = value);\n        });\n    }\n\n    return {sum: sum, dataExtent: dataExtent};\n}\n\n/**\n * Computes the score for the specified row,\n * as the worst aspect ratio.\n */\nfunction worst(row, rowFixedLength, ratio) {\n    var areaMax = 0;\n    var areaMin = Infinity;\n\n    for (var i = 0, area, len = row.length; i < len; i++) {\n        area = row[i].getLayout().area;\n        if (area) {\n            area < areaMin && (areaMin = area);\n            area > areaMax && (areaMax = area);\n        }\n    }\n\n    var squareArea = row.area * row.area;\n    var f = rowFixedLength * rowFixedLength * ratio;\n\n    return squareArea\n        ? mathMax$4(\n            (f * areaMax) / squareArea,\n            squareArea / (f * areaMin)\n        )\n        : Infinity;\n}\n\n/**\n * Positions the specified row of nodes. Modifies `rect`.\n */\nfunction position(row, rowFixedLength, rect, halfGapWidth, flush) {\n    // When rowFixedLength === rect.width,\n    // it is horizontal subdivision,\n    // rowFixedLength is the width of the subdivision,\n    // rowOtherLength is the height of the subdivision,\n    // and nodes will be positioned from left to right.\n\n    // wh[idx0WhenH] means: when horizontal,\n    //      wh[idx0WhenH] => wh[0] => 'width'.\n    //      xy[idx1WhenH] => xy[1] => 'y'.\n    var idx0WhenH = rowFixedLength === rect.width ? 0 : 1;\n    var idx1WhenH = 1 - idx0WhenH;\n    var xy = ['x', 'y'];\n    var wh = ['width', 'height'];\n\n    var last = rect[xy[idx0WhenH]];\n    var rowOtherLength = rowFixedLength\n        ? row.area / rowFixedLength : 0;\n\n    if (flush || rowOtherLength > rect[wh[idx1WhenH]]) {\n        rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow\n    }\n    for (var i = 0, rowLen = row.length; i < rowLen; i++) {\n        var node = row[i];\n        var nodeLayout = {};\n        var step = rowOtherLength\n            ? node.getLayout().area / rowOtherLength : 0;\n\n        var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax$4(rowOtherLength - 2 * halfGapWidth, 0);\n\n        // We use Math.max/min to avoid negative width/height when considering gap width.\n        var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last;\n        var modWH = (i === rowLen - 1 || remain < step) ? remain : step;\n        var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax$4(modWH - 2 * halfGapWidth, 0);\n\n        nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin$4(halfGapWidth, wh1 / 2);\n        nodeLayout[xy[idx0WhenH]] = last + mathMin$4(halfGapWidth, wh0 / 2);\n\n        last += modWH;\n        node.setLayout(nodeLayout, true);\n    }\n\n    rect[xy[idx1WhenH]] += rowOtherLength;\n    rect[wh[idx1WhenH]] -= rowOtherLength;\n}\n\n// Return [containerWidth, containerHeight] as defualt.\nfunction estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) {\n    // If targetInfo.node exists, we zoom to the node,\n    // so estimate whold width and heigth by target node.\n    var currNode = (targetInfo || {}).node;\n    var defaultSize = [containerWidth, containerHeight];\n\n    if (!currNode || currNode === viewRoot) {\n        return defaultSize;\n    }\n\n    var parent;\n    var viewArea = containerWidth * containerHeight;\n    var area = viewArea * seriesModel.option.zoomToNodeRatio;\n\n    while (parent = currNode.parentNode) { // jshint ignore:line\n        var sum = 0;\n        var siblings = parent.children;\n\n        for (var i = 0, len = siblings.length; i < len; i++) {\n            sum += siblings[i].getValue();\n        }\n        var currNodeValue = currNode.getValue();\n        if (currNodeValue === 0) {\n            return defaultSize;\n        }\n        area *= sum / currNodeValue;\n\n        // Considering border, suppose aspect ratio is 1.\n        var parentModel = parent.getModel();\n        var borderWidth = parentModel.get(PATH_BORDER_WIDTH);\n        var upperHeight = Math.max(borderWidth, getUpperLabelHeight(parentModel, borderWidth));\n        area += 4 * borderWidth * borderWidth\n            + (3 * borderWidth + upperHeight) * Math.pow(area, 0.5);\n\n        area > MAX_SAFE_INTEGER && (area = MAX_SAFE_INTEGER);\n\n        currNode = parent;\n    }\n\n    area < viewArea && (area = viewArea);\n    var scale = Math.pow(area / viewArea, 0.5);\n\n    return [containerWidth * scale, containerHeight * scale];\n}\n\n// Root postion base on coord of containerGroup\nfunction calculateRootPosition(layoutInfo, rootRect, targetInfo) {\n    if (rootRect) {\n        return {x: rootRect.x, y: rootRect.y};\n    }\n\n    var defaultPosition = {x: 0, y: 0};\n    if (!targetInfo) {\n        return defaultPosition;\n    }\n\n    // If targetInfo is fetched by 'retrieveTargetInfo',\n    // old tree and new tree are the same tree,\n    // so the node still exists and we can visit it.\n\n    var targetNode = targetInfo.node;\n    var layout = targetNode.getLayout();\n\n    if (!layout) {\n        return defaultPosition;\n    }\n\n    // Transform coord from local to container.\n    var targetCenter = [layout.width / 2, layout.height / 2];\n    var node = targetNode;\n    while (node) {\n        var nodeLayout = node.getLayout();\n        targetCenter[0] += nodeLayout.x;\n        targetCenter[1] += nodeLayout.y;\n        node = node.parentNode;\n    }\n\n    return {\n        x: layoutInfo.width / 2 - targetCenter[0],\n        y: layoutInfo.height / 2 - targetCenter[1]\n    };\n}\n\n// Mark nodes visible for prunning when visual coding and rendering.\n// Prunning depends on layout and root position, so we have to do it after layout.\nfunction prunning(node, clipRect, viewAbovePath, viewRoot, depth) {\n    var nodeLayout = node.getLayout();\n    var nodeInViewAbovePath = viewAbovePath[depth];\n    var isAboveViewRoot = nodeInViewAbovePath && nodeInViewAbovePath === node;\n\n    if (\n        (nodeInViewAbovePath && !isAboveViewRoot)\n        || (depth === viewAbovePath.length && node !== viewRoot)\n    ) {\n        return;\n    }\n\n    node.setLayout({\n        // isInView means: viewRoot sub tree + viewAbovePath\n        isInView: true,\n        // invisible only means: outside view clip so that the node can not\n        // see but still layout for animation preparation but not render.\n        invisible: !isAboveViewRoot && !clipRect.intersect(nodeLayout),\n        isAboveViewRoot: isAboveViewRoot\n    }, true);\n\n    // Transform to child coordinate.\n    var childClipRect = new BoundingRect(\n        clipRect.x - nodeLayout.x,\n        clipRect.y - nodeLayout.y,\n        clipRect.width,\n        clipRect.height\n    );\n\n    each$10(node.viewChildren || [], function (child) {\n        prunning(child, childClipRect, viewAbovePath, viewRoot, depth + 1);\n    });\n}\n\nfunction getUpperLabelHeight(model) {\n    return model.get(PATH_UPPER_LABEL_SHOW) ? model.get(PATH_UPPER_LABEL_HEIGHT) : 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(treemapVisual);\nregisterLayout(treemapLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Graph data structure\n *\n * @module echarts/data/Graph\n * @author Yi Shen(https://www.github.com/pissang)\n */\n\n// id may be function name of Object, add a prefix to avoid this problem.\nfunction generateNodeKey(id) {\n    return '_EC_' + id;\n}\n/**\n * @alias module:echarts/data/Graph\n * @constructor\n * @param {boolean} directed\n */\nvar Graph = function (directed) {\n    /**\n     * 是否是有向图\n     * @type {boolean}\n     * @private\n     */\n    this._directed = directed || false;\n\n    /**\n     * @type {Array.<module:echarts/data/Graph.Node>}\n     * @readOnly\n     */\n    this.nodes = [];\n\n    /**\n     * @type {Array.<module:echarts/data/Graph.Edge>}\n     * @readOnly\n     */\n    this.edges = [];\n\n    /**\n     * @type {Object.<string, module:echarts/data/Graph.Node>}\n     * @private\n     */\n    this._nodesMap = {};\n    /**\n     * @type {Object.<string, module:echarts/data/Graph.Edge>}\n     * @private\n     */\n    this._edgesMap = {};\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.data;\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.edgeData;\n};\n\nvar graphProto = Graph.prototype;\n/**\n * @type {string}\n */\ngraphProto.type = 'graph';\n\n/**\n * If is directed graph\n * @return {boolean}\n */\ngraphProto.isDirected = function () {\n    return this._directed;\n};\n\n/**\n * Add a new node\n * @param {string} id\n * @param {number} [dataIndex]\n */\ngraphProto.addNode = function (id, dataIndex) {\n    id = id || ('' + dataIndex);\n\n    var nodesMap = this._nodesMap;\n\n    if (nodesMap[generateNodeKey(id)]) {\n        if (__DEV__) {\n            console.error('Graph nodes have duplicate name or id');\n        }\n        return;\n    }\n\n    var node = new Node(id, dataIndex);\n    node.hostGraph = this;\n\n    this.nodes.push(node);\n\n    nodesMap[generateNodeKey(id)] = node;\n    return node;\n};\n\n/**\n * Get node by data index\n * @param  {number} dataIndex\n * @return {module:echarts/data/Graph~Node}\n */\ngraphProto.getNodeByIndex = function (dataIndex) {\n    var rawIdx = this.data.getRawIndex(dataIndex);\n    return this.nodes[rawIdx];\n};\n/**\n * Get node by id\n * @param  {string} id\n * @return {module:echarts/data/Graph.Node}\n */\ngraphProto.getNodeById = function (id) {\n    return this._nodesMap[generateNodeKey(id)];\n};\n\n/**\n * Add a new edge\n * @param {number|string|module:echarts/data/Graph.Node} n1\n * @param {number|string|module:echarts/data/Graph.Node} n2\n * @param {number} [dataIndex=-1]\n * @return {module:echarts/data/Graph.Edge}\n */\ngraphProto.addEdge = function (n1, n2, dataIndex) {\n    var nodesMap = this._nodesMap;\n    var edgesMap = this._edgesMap;\n\n    // PNEDING\n    if (typeof n1 === 'number') {\n        n1 = this.nodes[n1];\n    }\n    if (typeof n2 === 'number') {\n        n2 = this.nodes[n2];\n    }\n\n    if (!Node.isInstance(n1)) {\n        n1 = nodesMap[generateNodeKey(n1)];\n    }\n    if (!Node.isInstance(n2)) {\n        n2 = nodesMap[generateNodeKey(n2)];\n    }\n    if (!n1 || !n2) {\n        return;\n    }\n\n    var key = n1.id + '-' + n2.id;\n    // PENDING\n    if (edgesMap[key]) {\n        return;\n    }\n\n    var edge = new Edge(n1, n2, dataIndex);\n    edge.hostGraph = this;\n\n    if (this._directed) {\n        n1.outEdges.push(edge);\n        n2.inEdges.push(edge);\n    }\n    n1.edges.push(edge);\n    if (n1 !== n2) {\n        n2.edges.push(edge);\n    }\n\n    this.edges.push(edge);\n    edgesMap[key] = edge;\n\n    return edge;\n};\n\n/**\n * Get edge by data index\n * @param  {number} dataIndex\n * @return {module:echarts/data/Graph~Node}\n */\ngraphProto.getEdgeByIndex = function (dataIndex) {\n    var rawIdx = this.edgeData.getRawIndex(dataIndex);\n    return this.edges[rawIdx];\n};\n/**\n * Get edge by two linked nodes\n * @param  {module:echarts/data/Graph.Node|string} n1\n * @param  {module:echarts/data/Graph.Node|string} n2\n * @return {module:echarts/data/Graph.Edge}\n */\ngraphProto.getEdge = function (n1, n2) {\n    if (Node.isInstance(n1)) {\n        n1 = n1.id;\n    }\n    if (Node.isInstance(n2)) {\n        n2 = n2.id;\n    }\n\n    var edgesMap = this._edgesMap;\n\n    if (this._directed) {\n        return edgesMap[n1 + '-' + n2];\n    }\n    else {\n        return edgesMap[n1 + '-' + n2]\n            || edgesMap[n2 + '-' + n1];\n    }\n};\n\n/**\n * Iterate all nodes\n * @param  {Function} cb\n * @param  {*} [context]\n */\ngraphProto.eachNode = function (cb, context) {\n    var nodes = this.nodes;\n    var len = nodes.length;\n    for (var i = 0; i < len; i++) {\n        if (nodes[i].dataIndex >= 0) {\n            cb.call(context, nodes[i], i);\n        }\n    }\n};\n\n/**\n * Iterate all edges\n * @param  {Function} cb\n * @param  {*} [context]\n */\ngraphProto.eachEdge = function (cb, context) {\n    var edges = this.edges;\n    var len = edges.length;\n    for (var i = 0; i < len; i++) {\n        if (edges[i].dataIndex >= 0\n            && edges[i].node1.dataIndex >= 0\n            && edges[i].node2.dataIndex >= 0\n        ) {\n            cb.call(context, edges[i], i);\n        }\n    }\n};\n\n/**\n * Breadth first traverse\n * @param {Function} cb\n * @param {module:echarts/data/Graph.Node} startNode\n * @param {string} [direction='none'] 'none'|'in'|'out'\n * @param {*} [context]\n */\ngraphProto.breadthFirstTraverse = function (\n    cb, startNode, direction, context\n) {\n    if (!Node.isInstance(startNode)) {\n        startNode = this._nodesMap[generateNodeKey(startNode)];\n    }\n    if (!startNode) {\n        return;\n    }\n\n    var edgeType = direction === 'out'\n        ? 'outEdges' : (direction === 'in' ? 'inEdges' : 'edges');\n\n    for (var i = 0; i < this.nodes.length; i++) {\n        this.nodes[i].__visited = false;\n    }\n\n    if (cb.call(context, startNode, null)) {\n        return;\n    }\n\n    var queue = [startNode];\n    while (queue.length) {\n        var currentNode = queue.shift();\n        var edges = currentNode[edgeType];\n\n        for (var i = 0; i < edges.length; i++) {\n            var e = edges[i];\n            var otherNode = e.node1 === currentNode\n                ? e.node2 : e.node1;\n            if (!otherNode.__visited) {\n                if (cb.call(context, otherNode, currentNode)) {\n                    // Stop traversing\n                    return;\n                }\n                queue.push(otherNode);\n                otherNode.__visited = true;\n            }\n        }\n    }\n};\n\n// TODO\n// graphProto.depthFirstTraverse = function (\n//     cb, startNode, direction, context\n// ) {\n\n// };\n\n// Filter update\ngraphProto.update = function () {\n    var data = this.data;\n    var edgeData = this.edgeData;\n    var nodes = this.nodes;\n    var edges = this.edges;\n\n    for (var i = 0, len = nodes.length; i < len; i++) {\n        nodes[i].dataIndex = -1;\n    }\n    for (var i = 0, len = data.count(); i < len; i++) {\n        nodes[data.getRawIndex(i)].dataIndex = i;\n    }\n\n    edgeData.filterSelf(function (idx) {\n        var edge = edges[edgeData.getRawIndex(idx)];\n        return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0;\n    });\n\n    // Update edge\n    for (var i = 0, len = edges.length; i < len; i++) {\n        edges[i].dataIndex = -1;\n    }\n    for (var i = 0, len = edgeData.count(); i < len; i++) {\n        edges[edgeData.getRawIndex(i)].dataIndex = i;\n    }\n};\n\n/**\n * @return {module:echarts/data/Graph}\n */\ngraphProto.clone = function () {\n    var graph = new Graph(this._directed);\n    var nodes = this.nodes;\n    var edges = this.edges;\n    for (var i = 0; i < nodes.length; i++) {\n        graph.addNode(nodes[i].id, nodes[i].dataIndex);\n    }\n    for (var i = 0; i < edges.length; i++) {\n        var e = edges[i];\n        graph.addEdge(e.node1.id, e.node2.id, e.dataIndex);\n    }\n    return graph;\n};\n\n\n/**\n * @alias module:echarts/data/Graph.Node\n */\nfunction Node(id, dataIndex) {\n    /**\n    * @type {string}\n    */\n    this.id = id == null ? '' : id;\n\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.inEdges = [];\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.outEdges = [];\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.edges = [];\n    /**\n     * @type {module:echarts/data/Graph}\n     */\n    this.hostGraph;\n\n    /**\n     * @type {number}\n     */\n    this.dataIndex = dataIndex == null ? -1 : dataIndex;\n}\n\nNode.prototype = {\n\n    constructor: Node,\n\n    /**\n     * @return {number}\n     */\n    degree: function () {\n        return this.edges.length;\n    },\n\n    /**\n     * @return {number}\n     */\n    inDegree: function () {\n        return this.inEdges.length;\n    },\n\n    /**\n    * @return {number}\n    */\n    outDegree: function () {\n        return this.outEdges.length;\n    },\n\n    /**\n     * @param {string} [path]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path) {\n        if (this.dataIndex < 0) {\n            return;\n        }\n        var graph = this.hostGraph;\n        var itemModel = graph.data.getItemModel(this.dataIndex);\n\n        return itemModel.getModel(path);\n    }\n};\n\n/**\n * 图边\n * @alias module:echarts/data/Graph.Edge\n * @param {module:echarts/data/Graph.Node} n1\n * @param {module:echarts/data/Graph.Node} n2\n * @param {number} [dataIndex=-1]\n */\nfunction Edge(n1, n2, dataIndex) {\n\n    /**\n     * 节点1，如果是有向图则为源节点\n     * @type {module:echarts/data/Graph.Node}\n     */\n    this.node1 = n1;\n\n    /**\n     * 节点2，如果是有向图则为目标节点\n     * @type {module:echarts/data/Graph.Node}\n     */\n    this.node2 = n2;\n\n    this.dataIndex = dataIndex == null ? -1 : dataIndex;\n}\n\n/**\n * @param {string} [path]\n * @return {module:echarts/model/Model}\n */\nEdge.prototype.getModel = function (path) {\n    if (this.dataIndex < 0) {\n        return;\n    }\n    var graph = this.hostGraph;\n    var itemModel = graph.edgeData.getItemModel(this.dataIndex);\n\n    return itemModel.getModel(path);\n};\n\nvar createGraphDataProxyMixin = function (hostName, dataName) {\n    return {\n        /**\n         * @param {string=} [dimension='value'] Default 'value'. can be 'a', 'b', 'c', 'd', 'e'.\n         * @return {number}\n         */\n        getValue: function (dimension) {\n            var data = this[hostName][dataName];\n            return data.get(data.getDimension(dimension || 'value'), this.dataIndex);\n        },\n\n        /**\n         * @param {Object|string} key\n         * @param {*} [value]\n         */\n        setVisual: function (key, value) {\n            this.dataIndex >= 0\n                && this[hostName][dataName].setItemVisual(this.dataIndex, key, value);\n        },\n\n        /**\n         * @param {string} key\n         * @return {boolean}\n         */\n        getVisual: function (key, ignoreParent) {\n            return this[hostName][dataName].getItemVisual(this.dataIndex, key, ignoreParent);\n        },\n\n        /**\n         * @param {Object} layout\n         * @return {boolean} [merge=false]\n         */\n        setLayout: function (layout, merge$$1) {\n            this.dataIndex >= 0\n                && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge$$1);\n        },\n\n        /**\n         * @return {Object}\n         */\n        getLayout: function () {\n            return this[hostName][dataName].getItemLayout(this.dataIndex);\n        },\n\n        /**\n         * @return {module:zrender/Element}\n         */\n        getGraphicEl: function () {\n            return this[hostName][dataName].getItemGraphicEl(this.dataIndex);\n        },\n\n        /**\n         * @return {number}\n         */\n        getRawIndex: function () {\n            return this[hostName][dataName].getRawIndex(this.dataIndex);\n        }\n    };\n};\n\nmixin(Node, createGraphDataProxyMixin('hostGraph', 'data'));\nmixin(Edge, createGraphDataProxyMixin('hostGraph', 'edgeData'));\n\nGraph.Node = Node;\nGraph.Edge = Edge;\n\nenableClassCheck(Node);\nenableClassCheck(Edge);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createGraphFromNodeEdge = function (nodes, edges, seriesModel, directed, beforeLink) {\n    // ??? TODO\n    // support dataset?\n    var graph = new Graph(directed);\n    for (var i = 0; i < nodes.length; i++) {\n        graph.addNode(retrieve(\n            // Id, name, dataIndex\n            nodes[i].id, nodes[i].name, i\n        ), i);\n    }\n\n    var linkNameList = [];\n    var validEdges = [];\n    var linkCount = 0;\n    for (var i = 0; i < edges.length; i++) {\n        var link = edges[i];\n        var source = link.source;\n        var target = link.target;\n        // addEdge may fail when source or target not exists\n        if (graph.addEdge(source, target, linkCount)) {\n            validEdges.push(link);\n            linkNameList.push(retrieve(link.id, source + ' > ' + target));\n            linkCount++;\n        }\n    }\n\n    var coordSys = seriesModel.get('coordinateSystem');\n    var nodeData;\n    if (coordSys === 'cartesian2d' || coordSys === 'polar') {\n        nodeData = createListFromArray(nodes, seriesModel);\n    }\n    else {\n        var coordSysCtor = CoordinateSystemManager.get(coordSys);\n        var coordDimensions = (coordSysCtor && coordSysCtor.type !== 'view')\n            ? (coordSysCtor.dimensions || []) : [];\n        // FIXME: Some geo do not need `value` dimenson, whereas `calendar` needs\n        // `value` dimension, but graph need `value` dimension. It's better to\n        // uniform this behavior.\n        if (indexOf(coordDimensions, 'value') < 0) {\n            coordDimensions.concat(['value']);\n        }\n\n        var dimensionNames = createDimensions(nodes, {\n            coordDimensions: coordDimensions\n        });\n        nodeData = new List(dimensionNames, seriesModel);\n        nodeData.initData(nodes);\n    }\n\n    var edgeData = new List(['value'], seriesModel);\n    edgeData.initData(validEdges, linkNameList);\n\n    beforeLink && beforeLink(nodeData, edgeData);\n\n    linkList({\n        mainData: nodeData,\n        struct: graph,\n        structAttr: 'graph',\n        datas: {node: nodeData, edge: edgeData},\n        datasAttr: {node: 'data', edge: 'edgeData'}\n    });\n\n    // Update dataIndex of nodes and edges because invalid edge may be removed\n    graph.update();\n\n    return graph;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GraphSeries = extendSeriesModel({\n\n    type: 'series.graph',\n\n    init: function (option) {\n        GraphSeries.superApply(this, 'init', arguments);\n\n        // Provide data for legend select\n        this.legendDataProvider = function () {\n            return this._categoriesData;\n        };\n\n        this.fillDataTextStyle(option.edges || option.links);\n\n        this._updateCategoriesData();\n    },\n\n    mergeOption: function (option) {\n        GraphSeries.superApply(this, 'mergeOption', arguments);\n\n        this.fillDataTextStyle(option.edges || option.links);\n\n        this._updateCategoriesData();\n    },\n\n    mergeDefaultAndTheme: function (option) {\n        GraphSeries.superApply(this, 'mergeDefaultAndTheme', arguments);\n        defaultEmphasis(option, ['edgeLabel'], ['show']);\n    },\n\n    getInitialData: function (option, ecModel) {\n        var edges = option.edges || option.links || [];\n        var nodes = option.data || option.nodes || [];\n        var self = this;\n\n        if (nodes && edges) {\n            return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink).data;\n        }\n\n        function beforeLink(nodeData, edgeData) {\n            // Overwrite nodeData.getItemModel to\n            nodeData.wrapMethod('getItemModel', function (model) {\n                var categoriesModels = self._categoriesModels;\n                var categoryIdx = model.getShallow('category');\n                var categoryModel = categoriesModels[categoryIdx];\n                if (categoryModel) {\n                    categoryModel.parentModel = model.parentModel;\n                    model.parentModel = categoryModel;\n                }\n                return model;\n            });\n\n            var edgeLabelModel = self.getModel('edgeLabel');\n            // For option `edgeLabel` can be found by label.xxx.xxx on item mode.\n            var fakeSeriesModel = new Model(\n                {label: edgeLabelModel.option},\n                edgeLabelModel.parentModel,\n                ecModel\n            );\n            var emphasisEdgeLabelModel = self.getModel('emphasis.edgeLabel');\n            var emphasisFakeSeriesModel = new Model(\n                {emphasis: {label: emphasisEdgeLabelModel.option}},\n                emphasisEdgeLabelModel.parentModel,\n                ecModel\n            );\n\n            edgeData.wrapMethod('getItemModel', function (model) {\n                model.customizeGetParent(edgeGetParent);\n                return model;\n            });\n\n            function edgeGetParent(path) {\n                path = this.parsePath(path);\n                return (path && path[0] === 'label')\n                    ? fakeSeriesModel\n                    : (path && path[0] === 'emphasis' && path[1] === 'label')\n                    ? emphasisFakeSeriesModel\n                    : this.parentModel;\n            }\n        }\n    },\n\n    /**\n     * @return {module:echarts/data/Graph}\n     */\n    getGraph: function () {\n        return this.getData().graph;\n    },\n\n    /**\n     * @return {module:echarts/data/List}\n     */\n    getEdgeData: function () {\n        return this.getGraph().edgeData;\n    },\n\n    /**\n     * @return {module:echarts/data/List}\n     */\n    getCategoriesData: function () {\n        return this._categoriesData;\n    },\n\n    /**\n     * @override\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType) {\n        if (dataType === 'edge') {\n            var nodeData = this.getData();\n            var params = this.getDataParams(dataIndex, dataType);\n            var edge = nodeData.graph.getEdgeByIndex(dataIndex);\n            var sourceName = nodeData.getName(edge.node1.dataIndex);\n            var targetName = nodeData.getName(edge.node2.dataIndex);\n\n            var html = [];\n            sourceName != null && html.push(sourceName);\n            targetName != null && html.push(targetName);\n            html = encodeHTML(html.join(' > '));\n\n            if (params.value) {\n                html += ' : ' + encodeHTML(params.value);\n            }\n            return html;\n        }\n        else { // dataType === 'node' or empty\n            return GraphSeries.superApply(this, 'formatTooltip', arguments);\n        }\n    },\n\n    _updateCategoriesData: function () {\n        var categories = map(this.option.categories || [], function (category) {\n            // Data must has value\n            return category.value != null ? category : extend({\n                value: 0\n            }, category);\n        });\n        var categoriesData = new List(['value'], this);\n        categoriesData.initData(categories);\n\n        this._categoriesData = categoriesData;\n\n        this._categoriesModels = categoriesData.mapArray(function (idx) {\n            return categoriesData.getItemModel(idx, true);\n        });\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    isAnimationEnabled: function () {\n        return GraphSeries.superCall(this, 'isAnimationEnabled')\n            // Not enable animation when do force layout\n            && !(this.get('layout') === 'force' && this.get('force.layoutAnimation'));\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'view',\n\n        // Default option for all coordinate systems\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n        // polarIndex: 0,\n        // geoIndex: 0,\n\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        layout: null,\n\n        focusNodeAdjacency: false,\n\n        // Configuration of circular layout\n        circular: {\n            rotateLabel: false\n        },\n        // Configuration of force directed layout\n        force: {\n            initLayout: null,\n            // Node repulsion. Can be an array to represent range.\n            repulsion: [0, 50],\n            gravity: 0.1,\n\n            // Edge length. Can be an array to represent range.\n            edgeLength: 30,\n\n            layoutAnimation: true\n        },\n\n        left: 'center',\n        top: 'center',\n        // right: null,\n        // bottom: null,\n        // width: '80%',\n        // height: '80%',\n\n        symbol: 'circle',\n        symbolSize: 10,\n\n        edgeSymbol: ['none', 'none'],\n        edgeSymbolSize: 10,\n        edgeLabel: {\n            position: 'middle'\n        },\n\n        draggable: false,\n\n        roam: false,\n\n        // Default on center of graph\n        center: null,\n\n        zoom: 1,\n        // Symbol size scale ratio in roam\n        nodeScaleRatio: 0.6,\n        // cursor: null,\n\n        // categories: [],\n\n        // data: []\n        // Or\n        // nodes: []\n        //\n        // links: []\n        // Or\n        // edges: []\n\n        label: {\n            show: false,\n            formatter: '{b}'\n        },\n\n        itemStyle: {},\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            curveness: 0,\n            opacity: 0.5\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Line path for bezier and straight line draw\n */\n\nvar straightLineProto = Line.prototype;\nvar bezierCurveProto = BezierCurve.prototype;\n\nfunction isLine(shape) {\n    return isNaN(+shape.cpx1) || isNaN(+shape.cpy1);\n}\n\nvar LinePath = extendShape({\n\n    type: 'ec-line',\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        percent: 1,\n        cpx1: null,\n        cpy1: null\n    },\n\n    buildPath: function (ctx, shape) {\n        (isLine(shape) ? straightLineProto : bezierCurveProto).buildPath(ctx, shape);\n    },\n\n    pointAt: function (t) {\n        return isLine(this.shape)\n            ? straightLineProto.pointAt.call(this, t)\n            : bezierCurveProto.pointAt.call(this, t);\n    },\n\n    tangentAt: function (t) {\n        var shape = this.shape;\n        var p = isLine(shape)\n            ? [shape.x2 - shape.x1, shape.y2 - shape.y1]\n            : bezierCurveProto.tangentAt.call(this, t);\n        return normalize(p, p);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\nvar SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'];\n\nfunction makeSymbolTypeKey(symbolCategory) {\n    return '_' + symbolCategory + 'Type';\n}\n/**\n * @inner\n */\nfunction createSymbol$1(name, lineData, idx) {\n    var color = lineData.getItemVisual(idx, 'color');\n    var symbolType = lineData.getItemVisual(idx, name);\n    var symbolSize = lineData.getItemVisual(idx, name + 'Size');\n\n    if (!symbolType || symbolType === 'none') {\n        return;\n    }\n\n    if (!isArray(symbolSize)) {\n        symbolSize = [symbolSize, symbolSize];\n    }\n    var symbolPath = createSymbol(\n        symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2,\n        symbolSize[0], symbolSize[1], color\n    );\n\n    symbolPath.name = name;\n\n    return symbolPath;\n}\n\nfunction createLine(points) {\n    var line = new LinePath({\n        name: 'line'\n    });\n    setLinePoints(line.shape, points);\n    return line;\n}\n\nfunction setLinePoints(targetShape, points) {\n    var p1 = points[0];\n    var p2 = points[1];\n    var cp1 = points[2];\n    targetShape.x1 = p1[0];\n    targetShape.y1 = p1[1];\n    targetShape.x2 = p2[0];\n    targetShape.y2 = p2[1];\n    targetShape.percent = 1;\n\n    if (cp1) {\n        targetShape.cpx1 = cp1[0];\n        targetShape.cpy1 = cp1[1];\n    }\n    else {\n        targetShape.cpx1 = NaN;\n        targetShape.cpy1 = NaN;\n    }\n}\n\nfunction updateSymbolAndLabelBeforeLineUpdate() {\n    var lineGroup = this;\n    var symbolFrom = lineGroup.childOfName('fromSymbol');\n    var symbolTo = lineGroup.childOfName('toSymbol');\n    var label = lineGroup.childOfName('label');\n    // Quick reject\n    if (!symbolFrom && !symbolTo && label.ignore) {\n        return;\n    }\n\n    var invScale = 1;\n    var parentNode = this.parent;\n    while (parentNode) {\n        if (parentNode.scale) {\n            invScale /= parentNode.scale[0];\n        }\n        parentNode = parentNode.parent;\n    }\n\n    var line = lineGroup.childOfName('line');\n    // If line not changed\n    // FIXME Parent scale changed\n    if (!this.__dirty && !line.__dirty) {\n        return;\n    }\n\n    var percent = line.shape.percent;\n    var fromPos = line.pointAt(0);\n    var toPos = line.pointAt(percent);\n\n    var d = sub([], toPos, fromPos);\n    normalize(d, d);\n\n    if (symbolFrom) {\n        symbolFrom.attr('position', fromPos);\n        var tangent = line.tangentAt(0);\n        symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolFrom.attr('scale', [invScale * percent, invScale * percent]);\n    }\n    if (symbolTo) {\n        symbolTo.attr('position', toPos);\n        var tangent = line.tangentAt(1);\n        symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolTo.attr('scale', [invScale * percent, invScale * percent]);\n    }\n\n    if (!label.ignore) {\n        label.attr('position', toPos);\n\n        var textPosition;\n        var textAlign;\n        var textVerticalAlign;\n\n        var distance$$1 = 5 * invScale;\n        // End\n        if (label.__position === 'end') {\n            textPosition = [d[0] * distance$$1 + toPos[0], d[1] * distance$$1 + toPos[1]];\n            textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');\n        }\n        // Middle\n        else if (label.__position === 'middle') {\n            var halfPercent = percent / 2;\n            var tangent = line.tangentAt(halfPercent);\n            var n = [tangent[1], -tangent[0]];\n            var cp = line.pointAt(halfPercent);\n            if (n[1] > 0) {\n                n[0] = -n[0];\n                n[1] = -n[1];\n            }\n            textPosition = [cp[0] + n[0] * distance$$1, cp[1] + n[1] * distance$$1];\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            var rotation = -Math.atan2(tangent[1], tangent[0]);\n            if (toPos[0] < fromPos[0]) {\n                rotation = Math.PI + rotation;\n            }\n            label.attr('rotation', rotation);\n        }\n        // Start\n        else {\n            textPosition = [-d[0] * distance$$1 + fromPos[0], -d[1] * distance$$1 + fromPos[1]];\n            textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');\n        }\n        label.attr({\n            style: {\n                // Use the user specified text align and baseline first\n                textVerticalAlign: label.__verticalAlign || textVerticalAlign,\n                textAlign: label.__textAlign || textAlign\n            },\n            position: textPosition,\n            scale: [invScale, invScale]\n        });\n    }\n}\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction Line$1(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createLine(lineData, idx, seriesScope);\n}\n\nvar lineProto = Line$1.prototype;\n\n// Update symbol position and rotation\nlineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate;\n\nlineProto._createLine = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n    var linePoints = lineData.getItemLayout(idx);\n\n    var line = createLine(linePoints);\n    line.shape.percent = 0;\n    initProps(line, {\n        shape: {\n            percent: 1\n        }\n    }, seriesModel, idx);\n\n    this.add(line);\n\n    var label = new Text({\n        name: 'label',\n        // FIXME\n        // Temporary solution for `focusNodeAdjacency`.\n        // line label do not use the opacity of lineStyle.\n        lineLabelOriginalOpacity: 1\n    });\n    this.add(label);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = createSymbol$1(symbolCategory, lineData, idx);\n        // symbols must added after line to make sure\n        // it will be updated after line#update.\n        // Or symbol position and rotation update in line#beforeUpdate will be one frame slow\n        this.add(symbol);\n        this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory);\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n    var linePoints = lineData.getItemLayout(idx);\n    var target = {\n        shape: {}\n    };\n    setLinePoints(target.shape, linePoints);\n    updateProps(line, target, seriesModel, idx);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbolType = lineData.getItemVisual(idx, symbolCategory);\n        var key = makeSymbolTypeKey(symbolCategory);\n        // Symbol changed\n        if (this[key] !== symbolType) {\n            this.remove(this.childOfName(symbolCategory));\n            var symbol = createSymbol$1(symbolCategory, lineData, idx);\n            this.add(symbol);\n        }\n        this[key] = symbolType;\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n\n    // Optimization for large dataset\n    if (!seriesScope || lineData.hasItemOption) {\n        var itemModel = lineData.getItemModel(idx);\n\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n        labelModel = itemModel.getModel('label');\n        hoverLabelModel = itemModel.getModel('emphasis.label');\n    }\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n    var visualOpacity = retrieve3(\n        lineData.getItemVisual(idx, 'opacity'),\n        lineStyle.opacity,\n        1\n    );\n\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor,\n            opacity: visualOpacity\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    // Update symbol\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = this.childOfName(symbolCategory);\n        if (symbol) {\n            symbol.setColor(visualColor);\n            symbol.setStyle({\n                opacity: visualOpacity\n            });\n        }\n    }, this);\n\n    var showLabel = labelModel.getShallow('show');\n    var hoverShowLabel = hoverLabelModel.getShallow('show');\n\n    var label = this.childOfName('label');\n    var defaultLabelColor;\n    var baseText;\n\n    // FIXME: the logic below probably should be merged to `graphic.setLabelStyle`.\n    if (showLabel || hoverShowLabel) {\n        defaultLabelColor = visualColor || '#000';\n\n        baseText = seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType);\n        if (baseText == null) {\n            var rawVal = seriesModel.getRawValue(idx);\n            baseText = rawVal == null\n                ? lineData.getName(idx)\n                : isFinite(rawVal)\n                ? round$2(rawVal)\n                : rawVal;\n        }\n    }\n    var normalText = showLabel ? baseText : null;\n    var emphasisText = hoverShowLabel\n        ? retrieve2(\n            seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType),\n            baseText\n        )\n        : null;\n\n    var labelStyle = label.style;\n\n    // Always set `textStyle` even if `normalStyle.text` is null, because default\n    // values have to be set on `normalStyle`.\n    if (normalText != null || emphasisText != null) {\n        setTextStyle(label.style, labelModel, {\n            text: normalText\n        }, {\n            autoColor: defaultLabelColor\n        });\n\n        label.__textAlign = labelStyle.textAlign;\n        label.__verticalAlign = labelStyle.textVerticalAlign;\n        // 'start', 'middle', 'end'\n        label.__position = labelModel.get('position') || 'middle';\n    }\n\n    if (emphasisText != null) {\n        // Only these properties supported in this emphasis style here.\n        label.hoverStyle = {\n            text: emphasisText,\n            textFill: hoverLabelModel.getTextColor(true),\n            // For merging hover style to normal style, do not use\n            // `hoverLabelModel.getFont()` here.\n            fontStyle: hoverLabelModel.getShallow('fontStyle'),\n            fontWeight: hoverLabelModel.getShallow('fontWeight'),\n            fontSize: hoverLabelModel.getShallow('fontSize'),\n            fontFamily: hoverLabelModel.getShallow('fontFamily')\n        };\n    }\n    else {\n        label.hoverStyle = {\n            text: null\n        };\n    }\n\n    label.ignore = !showLabel && !hoverShowLabel;\n\n    setHoverStyle(this);\n};\n\nlineProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\nlineProto.downplay = function () {\n    this.trigger('normal');\n};\n\nlineProto.updateLayout = function (lineData, idx) {\n    this.setLinePoints(lineData.getItemLayout(idx));\n};\n\nlineProto.setLinePoints = function (points) {\n    var linePath = this.childOfName('line');\n    setLinePoints(linePath.shape, points);\n    linePath.dirty();\n};\n\ninherits(Line$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/LineDraw\n */\n\n// import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';\n\n/**\n * @alias module:echarts/component/marker/LineDraw\n * @constructor\n */\nfunction LineDraw(ctor) {\n    this._ctor = ctor || Line$1;\n\n    this.group = new Group();\n}\n\nvar lineDrawProto = LineDraw.prototype;\n\nlineDrawProto.isPersistent = function () {\n    return true;\n};\n\n/**\n * @param {module:echarts/data/List} lineData\n */\nlineDrawProto.updateData = function (lineData) {\n    var lineDraw = this;\n    var group = lineDraw.group;\n\n    var oldLineData = lineDraw._lineData;\n    lineDraw._lineData = lineData;\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldLineData) {\n        group.removeAll();\n    }\n\n    var seriesScope = makeSeriesScope$1(lineData);\n\n    lineData.diff(oldLineData)\n        .add(function (idx) {\n            doAdd(lineDraw, lineData, idx, seriesScope);\n        })\n        .update(function (newIdx, oldIdx) {\n            doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);\n        })\n        .remove(function (idx) {\n            group.remove(oldLineData.getItemGraphicEl(idx));\n        })\n        .execute();\n};\n\nfunction doAdd(lineDraw, lineData, idx, seriesScope) {\n    var itemLayout = lineData.getItemLayout(idx);\n\n    if (!lineNeedsDraw(itemLayout)) {\n        return;\n    }\n\n    var el = new lineDraw._ctor(lineData, idx, seriesScope);\n    lineData.setItemGraphicEl(idx, el);\n    lineDraw.group.add(el);\n}\n\nfunction doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {\n    var itemEl = oldLineData.getItemGraphicEl(oldIdx);\n\n    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {\n        lineDraw.group.remove(itemEl);\n        return;\n    }\n\n    if (!itemEl) {\n        itemEl = new lineDraw._ctor(newLineData, newIdx, seriesScope);\n    }\n    else {\n        itemEl.updateData(newLineData, newIdx, seriesScope);\n    }\n\n    newLineData.setItemGraphicEl(newIdx, itemEl);\n\n    lineDraw.group.add(itemEl);\n}\n\nlineDrawProto.updateLayout = function () {\n    var lineData = this._lineData;\n\n    // Do not support update layout in incremental mode.\n    if (!lineData) {\n        return;\n    }\n\n    lineData.eachItemGraphicEl(function (el, idx) {\n        el.updateLayout(lineData, idx);\n    }, this);\n};\n\nlineDrawProto.incrementalPrepareUpdate = function (lineData) {\n    this._seriesScope = makeSeriesScope$1(lineData);\n    this._lineData = null;\n    this.group.removeAll();\n};\n\nlineDrawProto.incrementalUpdate = function (taskParams, lineData) {\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var itemLayout = lineData.getItemLayout(idx);\n\n        if (lineNeedsDraw(itemLayout)) {\n            var el = new this._ctor(lineData, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n\n            this.group.add(el);\n            lineData.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction makeSeriesScope$1(lineData) {\n    var hostModel = lineData.hostModel;\n    return {\n        lineStyle: hostModel.getModel('lineStyle').getLineStyle(),\n        hoverLineStyle: hostModel.getModel('emphasis.lineStyle').getLineStyle(),\n        labelModel: hostModel.getModel('label'),\n        hoverLabelModel: hostModel.getModel('emphasis.label')\n    };\n}\n\nlineDrawProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlineDrawProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\nfunction isPointNaN(pt) {\n    return isNaN(pt[0]) || isNaN(pt[1]);\n}\n\nfunction lineNeedsDraw(pts) {\n    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar v1 = [];\nvar v2 = [];\nvar v3 = [];\nvar quadraticAt$1 = quadraticAt;\nvar v2DistSquare = distSquare;\nvar mathAbs$1 = Math.abs;\nfunction intersectCurveCircle(curvePoints, center, radius) {\n    var p0 = curvePoints[0];\n    var p1 = curvePoints[1];\n    var p2 = curvePoints[2];\n\n    var d = Infinity;\n    var t;\n    var radiusSquare = radius * radius;\n    var interval = 0.1;\n\n    for (var _t = 0.1; _t <= 0.9; _t += 0.1) {\n        v1[0] = quadraticAt$1(p0[0], p1[0], p2[0], _t);\n        v1[1] = quadraticAt$1(p0[1], p1[1], p2[1], _t);\n        var diff = mathAbs$1(v2DistSquare(v1, center) - radiusSquare);\n        if (diff < d) {\n            d = diff;\n            t = _t;\n        }\n    }\n\n    // Assume the segment is monotone，Find root through Bisection method\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        // var prev = t - interval;\n        var next = t + interval;\n        // v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev);\n        // v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev);\n        v2[0] = quadraticAt$1(p0[0], p1[0], p2[0], t);\n        v2[1] = quadraticAt$1(p0[1], p1[1], p2[1], t);\n        v3[0] = quadraticAt$1(p0[0], p1[0], p2[0], next);\n        v3[1] = quadraticAt$1(p0[1], p1[1], p2[1], next);\n\n        var diff = v2DistSquare(v2, center) - radiusSquare;\n        if (mathAbs$1(diff) < 1e-2) {\n            break;\n        }\n\n        // var prevDiff = v2DistSquare(v1, center) - radiusSquare;\n        var nextDiff = v2DistSquare(v3, center) - radiusSquare;\n\n        interval /= 2;\n        if (diff < 0) {\n            if (nextDiff >= 0) {\n                t = t + interval;\n            }\n            else {\n                t = t - interval;\n            }\n        }\n        else {\n            if (nextDiff >= 0) {\n                t = t - interval;\n            }\n            else {\n                t = t + interval;\n            }\n        }\n    }\n\n    return t;\n}\n\n// Adjust edge to avoid\nvar adjustEdge = function (graph, scale$$1) {\n    var tmp0 = [];\n    var quadraticSubdivide$$1 = quadraticSubdivide;\n    var pts = [[], [], []];\n    var pts2 = [[], []];\n    var v = [];\n    scale$$1 /= 2;\n\n    function getSymbolSize(node) {\n        var symbolSize = node.getVisual('symbolSize');\n        if (symbolSize instanceof Array) {\n            symbolSize = (symbolSize[0] + symbolSize[1]) / 2;\n        }\n        return symbolSize;\n    }\n    graph.eachEdge(function (edge, idx) {\n        var linePoints = edge.getLayout();\n        var fromSymbol = edge.getVisual('fromSymbol');\n        var toSymbol = edge.getVisual('toSymbol');\n\n        if (!linePoints.__original) {\n            linePoints.__original = [\n                clone$1(linePoints[0]),\n                clone$1(linePoints[1])\n            ];\n            if (linePoints[2]) {\n                linePoints.__original.push(clone$1(linePoints[2]));\n            }\n        }\n        var originalPoints = linePoints.__original;\n        // Quadratic curve\n        if (linePoints[2] != null) {\n            copy(pts[0], originalPoints[0]);\n            copy(pts[1], originalPoints[2]);\n            copy(pts[2], originalPoints[1]);\n            if (fromSymbol && fromSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node1);\n\n                var t = intersectCurveCircle(pts, originalPoints[0], symbolSize * scale$$1);\n                // Subdivide and get the second\n                quadraticSubdivide$$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0);\n                pts[0][0] = tmp0[3];\n                pts[1][0] = tmp0[4];\n                quadraticSubdivide$$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0);\n                pts[0][1] = tmp0[3];\n                pts[1][1] = tmp0[4];\n            }\n            if (toSymbol && toSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node2);\n\n                var t = intersectCurveCircle(pts, originalPoints[1], symbolSize * scale$$1);\n                // Subdivide and get the first\n                quadraticSubdivide$$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0);\n                pts[1][0] = tmp0[1];\n                pts[2][0] = tmp0[2];\n                quadraticSubdivide$$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0);\n                pts[1][1] = tmp0[1];\n                pts[2][1] = tmp0[2];\n            }\n            // Copy back to layout\n            copy(linePoints[0], pts[0]);\n            copy(linePoints[1], pts[2]);\n            copy(linePoints[2], pts[1]);\n        }\n        // Line\n        else {\n            copy(pts2[0], originalPoints[0]);\n            copy(pts2[1], originalPoints[1]);\n\n            sub(v, pts2[1], pts2[0]);\n            normalize(v, v);\n            if (fromSymbol && fromSymbol !== 'none') {\n\n                var symbolSize = getSymbolSize(edge.node1);\n\n                scaleAndAdd(pts2[0], pts2[0], v, symbolSize * scale$$1);\n            }\n            if (toSymbol && toSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node2);\n\n                scaleAndAdd(pts2[1], pts2[1], v, -symbolSize * scale$$1);\n            }\n            copy(linePoints[0], pts2[0]);\n            copy(linePoints[1], pts2[1]);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar FOCUS_ADJACENCY = '__focusNodeAdjacency';\nvar UNFOCUS_ADJACENCY = '__unfocusNodeAdjacency';\n\nvar nodeOpacityPath = ['itemStyle', 'opacity'];\nvar lineOpacityPath = ['lineStyle', 'opacity'];\n\nfunction getItemOpacity(item, opacityPath) {\n    return item.getVisual('opacity') || item.getModel().get(opacityPath);\n}\n\nfunction fadeOutItem(item, opacityPath, opacityRatio) {\n    var el = item.getGraphicEl();\n\n    var opacity = getItemOpacity(item, opacityPath);\n    if (opacityRatio != null) {\n        opacity == null && (opacity = 1);\n        opacity *= opacityRatio;\n    }\n\n    el.downplay && el.downplay();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            var opct = child.lineLabelOriginalOpacity;\n            if (opct == null || opacityRatio != null) {\n                opct = opacity;\n            }\n            child.setStyle('opacity', opct);\n        }\n    });\n}\n\nfunction fadeInItem(item, opacityPath) {\n    var opacity = getItemOpacity(item, opacityPath);\n    var el = item.getGraphicEl();\n\n    el.highlight && el.highlight();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nextendChartView({\n\n    type: 'graph',\n\n    init: function (ecModel, api) {\n        var symbolDraw = new SymbolDraw();\n        var lineDraw = new LineDraw();\n        var group = this.group;\n\n        this._controller = new RoamController(api.getZr());\n        this._controllerHost = {target: group};\n\n        group.add(symbolDraw.group);\n        group.add(lineDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineDraw = lineDraw;\n\n        this._firstRender = true;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        this._model = seriesModel;\n        this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');\n\n        var symbolDraw = this._symbolDraw;\n        var lineDraw = this._lineDraw;\n\n        var group = this.group;\n\n        if (coordSys.type === 'view') {\n            var groupNewProp = {\n                position: coordSys.position,\n                scale: coordSys.scale\n            };\n            if (this._firstRender) {\n                group.attr(groupNewProp);\n            }\n            else {\n                updateProps(group, groupNewProp, seriesModel);\n            }\n        }\n        // Fix edge contact point with node\n        adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n\n        var data = seriesModel.getData();\n        symbolDraw.updateData(data);\n\n        var edgeData = seriesModel.getEdgeData();\n        lineDraw.updateData(edgeData);\n\n        this._updateNodeAndLinkScale();\n\n        this._updateController(seriesModel, ecModel, api);\n\n        clearTimeout(this._layoutTimeout);\n        var forceLayout = seriesModel.forceLayout;\n        var layoutAnimation = seriesModel.get('force.layoutAnimation');\n        if (forceLayout) {\n            this._startForceLayoutIteration(forceLayout, layoutAnimation);\n        }\n\n        data.eachItemGraphicEl(function (el, idx) {\n            var itemModel = data.getItemModel(idx);\n            // Update draggable\n            el.off('drag').off('dragend');\n            var draggable = itemModel.get('draggable');\n            if (draggable) {\n                el.on('drag', function () {\n                    if (forceLayout) {\n                        forceLayout.warmUp();\n                        !this._layouting\n                            && this._startForceLayoutIteration(forceLayout, layoutAnimation);\n                        forceLayout.setFixed(idx);\n                        // Write position back to layout\n                        data.setItemLayout(idx, el.position);\n                    }\n                }, this).on('dragend', function () {\n                    if (forceLayout) {\n                        forceLayout.setUnfixed(idx);\n                    }\n                }, this);\n            }\n            el.setDraggable(draggable && forceLayout);\n\n            el[FOCUS_ADJACENCY] && el.off('mouseover', el[FOCUS_ADJACENCY]);\n            el[UNFOCUS_ADJACENCY] && el.off('mouseout', el[UNFOCUS_ADJACENCY]);\n\n            if (itemModel.get('focusNodeAdjacency')) {\n                el.on('mouseover', el[FOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'focusNodeAdjacency',\n                        seriesId: seriesModel.id,\n                        dataIndex: el.dataIndex\n                    });\n                });\n                el.on('mouseout', el[UNFOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'unfocusNodeAdjacency',\n                        seriesId: seriesModel.id\n                    });\n                });\n            }\n\n        }, this);\n\n        data.graph.eachEdge(function (edge) {\n            var el = edge.getGraphicEl();\n\n            el[FOCUS_ADJACENCY] && el.off('mouseover', el[FOCUS_ADJACENCY]);\n            el[UNFOCUS_ADJACENCY] && el.off('mouseout', el[UNFOCUS_ADJACENCY]);\n\n            if (edge.getModel().get('focusNodeAdjacency')) {\n                el.on('mouseover', el[FOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'focusNodeAdjacency',\n                        seriesId: seriesModel.id,\n                        edgeDataIndex: edge.dataIndex\n                    });\n                });\n                el.on('mouseout', el[UNFOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'unfocusNodeAdjacency',\n                        seriesId: seriesModel.id\n                    });\n                });\n            }\n        });\n\n        var circularRotateLabel = seriesModel.get('layout') === 'circular'\n            && seriesModel.get('circular.rotateLabel');\n        var cx = data.getLayout('cx');\n        var cy = data.getLayout('cy');\n        data.eachItemGraphicEl(function (el, idx) {\n            var symbolPath = el.getSymbolPath();\n            if (circularRotateLabel) {\n                var pos = data.getItemLayout(idx);\n                var rad = Math.atan2(pos[1] - cy, pos[0] - cx);\n                if (rad < 0) {\n                    rad = Math.PI * 2 + rad;\n                }\n                var isLeft = pos[0] < cx;\n                if (isLeft) {\n                    rad = rad - Math.PI;\n                }\n                var textPosition = isLeft ? 'left' : 'right';\n                symbolPath.setStyle({\n                    textRotation: -rad,\n                    textPosition: textPosition,\n                    textOrigin: 'center'\n                });\n                symbolPath.hoverStyle && (symbolPath.hoverStyle.textPosition = textPosition);\n            }\n            else {\n                symbolPath.setStyle({\n                    textRotation: 0\n                });\n            }\n        });\n\n        this._firstRender = false;\n    },\n\n    dispose: function () {\n        this._controller && this._controller.dispose();\n        this._controllerHost = {};\n    },\n\n    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var data = this._model.getData();\n        var graph = data.graph;\n        var dataIndex = payload.dataIndex;\n        var edgeDataIndex = payload.edgeDataIndex;\n\n        var node = graph.getNodeByIndex(dataIndex);\n        var edge = graph.getEdgeByIndex(edgeDataIndex);\n\n        if (!node && !edge) {\n            return;\n        }\n\n        graph.eachNode(function (node) {\n            fadeOutItem(node, nodeOpacityPath, 0.1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem(edge, lineOpacityPath, 0.1);\n        });\n\n        if (node) {\n            fadeInItem(node, nodeOpacityPath);\n            each$1(node.edges, function (adjacentEdge) {\n                if (adjacentEdge.dataIndex < 0) {\n                    return;\n                }\n                fadeInItem(adjacentEdge, lineOpacityPath);\n                fadeInItem(adjacentEdge.node1, nodeOpacityPath);\n                fadeInItem(adjacentEdge.node2, nodeOpacityPath);\n            });\n        }\n        if (edge) {\n            fadeInItem(edge, lineOpacityPath);\n            fadeInItem(edge.node1, nodeOpacityPath);\n            fadeInItem(edge.node2, nodeOpacityPath);\n        }\n    },\n\n    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var graph = this._model.getData().graph;\n\n        graph.eachNode(function (node) {\n            fadeOutItem(node, nodeOpacityPath);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem(edge, lineOpacityPath);\n        });\n    },\n\n    _startForceLayoutIteration: function (forceLayout, layoutAnimation) {\n        var self = this;\n        (function step() {\n            forceLayout.step(function (stopped) {\n                self.updateLayout(self._model);\n                (self._layouting = !stopped) && (\n                    layoutAnimation\n                        ? (self._layoutTimeout = setTimeout(step, 16))\n                        : step()\n                );\n            });\n        })();\n    },\n\n    _updateController: function (seriesModel, ecModel, api) {\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n        var group = this.group;\n\n        controller.setPointerChecker(function (e, x, y) {\n            var rect = group.getBoundingRect();\n            rect.applyTransform(group.transform);\n            return rect.contain(x, y)\n                && !onIrrelevantElement(e, api, seriesModel);\n        });\n\n        if (seriesModel.coordinateSystem.type !== 'view') {\n            controller.disable();\n            return;\n        }\n        controller.enable(seriesModel.get('roam'));\n        controllerHost.zoomLimit = seriesModel.get('scaleLimit');\n        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();\n\n        controller\n            .off('pan')\n            .off('zoom')\n            .on('pan', function (e) {\n                updateViewOnPan(controllerHost, e.dx, e.dy);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'graphRoam',\n                    dx: e.dx,\n                    dy: e.dy\n                });\n            })\n            .on('zoom', function (e) {\n                updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'graphRoam',\n                    zoom: e.scale,\n                    originX: e.originX,\n                    originY: e.originY\n                });\n                this._updateNodeAndLinkScale();\n                adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n                this._lineDraw.updateLayout();\n            }, this);\n    },\n\n    _updateNodeAndLinkScale: function () {\n        var seriesModel = this._model;\n        var data = seriesModel.getData();\n\n        var nodeScale = this._getNodeGlobalScale(seriesModel);\n        var invScale = [nodeScale, nodeScale];\n\n        data.eachItemGraphicEl(function (el, idx) {\n            el.attr('scale', invScale);\n        });\n    },\n\n    _getNodeGlobalScale: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type !== 'view') {\n            return 1;\n        }\n\n        var nodeScaleRatio = this._nodeScaleRatio;\n\n        var groupScale = coordSys.scale;\n        var groupZoom = (groupScale && groupScale[0]) || 1;\n        // Scale node when zoom changes\n        var roamZoom = coordSys.getZoom();\n        var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;\n\n        return nodeScale / groupZoom;\n    },\n\n    updateLayout: function (seriesModel) {\n        adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n\n        this._symbolDraw.updateLayout();\n        this._lineDraw.updateLayout();\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove();\n        this._lineDraw && this._lineDraw.remove();\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {number} [seriesIndex]\n * @property {string} [seriesId]\n * @property {string} [seriesName]\n * @property {number} [dataIndex]\n */\nregisterAction({\n    type: 'focusNodeAdjacency',\n    event: 'focusNodeAdjacency',\n    update: 'series:focusNodeAdjacency'\n}, function () {});\n\n/**\n * @payload\n * @property {number} [seriesIndex]\n * @property {string} [seriesId]\n * @property {string} [seriesName]\n */\nregisterAction({\n    type: 'unfocusNodeAdjacency',\n    event: 'unfocusNodeAdjacency',\n    update: 'series:unfocusNodeAdjacency'\n}, function () {});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar actionInfo = {\n    type: 'graphRoam',\n    event: 'graphRoam',\n    update: 'none'\n};\n\n/**\n * @payload\n * @property {string} name Series name\n * @property {number} [dx]\n * @property {number} [dy]\n * @property {number} [zoom]\n * @property {number} [originX]\n * @property {number} [originY]\n */\nregisterAction(actionInfo, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', query: payload}, function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        var res = updateCenterAndZoom(coordSys, payload);\n\n        seriesModel.setCenter\n            && seriesModel.setCenter(res.center);\n\n        seriesModel.setZoom\n            && seriesModel.setZoom(res.zoom);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar categoryFilter = function (ecModel) {\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (!legendModels || !legendModels.length) {\n        return;\n    }\n    ecModel.eachSeriesByType('graph', function (graphSeries) {\n        var categoriesData = graphSeries.getCategoriesData();\n        var graph = graphSeries.getGraph();\n        var data = graph.data;\n\n        var categoryNames = categoriesData.mapArray(categoriesData.getName);\n\n        data.filterSelf(function (idx) {\n            var model = data.getItemModel(idx);\n            var category = model.getShallow('category');\n            if (category != null) {\n                if (typeof category === 'number') {\n                    category = categoryNames[category];\n                }\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(category)) {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        });\n    }, this);\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar categoryVisual = function (ecModel) {\n\n    var paletteScope = {};\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var categoriesData = seriesModel.getCategoriesData();\n        var data = seriesModel.getData();\n\n        var categoryNameIdxMap = {};\n\n        categoriesData.each(function (idx) {\n            var name = categoriesData.getName(idx);\n            // Add prefix to avoid conflict with Object.prototype.\n            categoryNameIdxMap['ec-' + name] = idx;\n\n            var itemModel = categoriesData.getItemModel(idx);\n            var color = itemModel.get('itemStyle.color')\n                || seriesModel.getColorFromPalette(name, paletteScope);\n            categoriesData.setItemVisual(idx, 'color', color);\n        });\n\n        // Assign category color to visual\n        if (categoriesData.count()) {\n            data.each(function (idx) {\n                var model = data.getItemModel(idx);\n                var category = model.getShallow('category');\n                if (category != null) {\n                    if (typeof category === 'string') {\n                        category = categoryNameIdxMap['ec-' + category];\n                    }\n                    if (!data.getItemVisual(idx, 'color', true)) {\n                        data.setItemVisual(\n                            idx, 'color',\n                            categoriesData.getItemVisual(category, 'color')\n                        );\n                    }\n                }\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction normalize$1(a) {\n    if (!(a instanceof Array)) {\n        a = [a, a];\n    }\n    return a;\n}\n\nvar edgeVisual = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var graph = seriesModel.getGraph();\n        var edgeData = seriesModel.getEdgeData();\n        var symbolType = normalize$1(seriesModel.get('edgeSymbol'));\n        var symbolSize = normalize$1(seriesModel.get('edgeSymbolSize'));\n\n        var colorQuery = 'lineStyle.color'.split('.');\n        var opacityQuery = 'lineStyle.opacity'.split('.');\n\n        edgeData.setVisual('fromSymbol', symbolType && symbolType[0]);\n        edgeData.setVisual('toSymbol', symbolType && symbolType[1]);\n        edgeData.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);\n        edgeData.setVisual('toSymbolSize', symbolSize && symbolSize[1]);\n        edgeData.setVisual('color', seriesModel.get(colorQuery));\n        edgeData.setVisual('opacity', seriesModel.get(opacityQuery));\n\n        edgeData.each(function (idx) {\n            var itemModel = edgeData.getItemModel(idx);\n            var edge = graph.getEdgeByIndex(idx);\n            var symbolType = normalize$1(itemModel.getShallow('symbol', true));\n            var symbolSize = normalize$1(itemModel.getShallow('symbolSize', true));\n            // Edge visual must after node visual\n            var color = itemModel.get(colorQuery);\n            var opacity = itemModel.get(opacityQuery);\n            switch (color) {\n                case 'source':\n                    color = edge.node1.getVisual('color');\n                    break;\n                case 'target':\n                    color = edge.node2.getVisual('color');\n                    break;\n            }\n\n            symbolType[0] && edge.setVisual('fromSymbol', symbolType[0]);\n            symbolType[1] && edge.setVisual('toSymbol', symbolType[1]);\n            symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]);\n            symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]);\n\n            edge.setVisual('color', color);\n            edge.setVisual('opacity', opacity);\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction simpleLayout$1(seriesModel) {\n    var coordSys = seriesModel.coordinateSystem;\n    if (coordSys && coordSys.type !== 'view') {\n        return;\n    }\n    var graph = seriesModel.getGraph();\n\n    graph.eachNode(function (node) {\n        var model = node.getModel();\n        node.setLayout([+model.get('x'), +model.get('y')]);\n    });\n\n    simpleLayoutEdge(graph);\n}\n\nfunction simpleLayoutEdge(graph) {\n    graph.eachEdge(function (edge) {\n        var curveness = edge.getModel().get('lineStyle.curveness') || 0;\n        var p1 = clone$1(edge.node1.getLayout());\n        var p2 = clone$1(edge.node2.getLayout());\n        var points = [p1, p2];\n        if (+curveness) {\n            points.push([\n                (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness,\n                (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness\n            ]);\n        }\n        edge.setLayout(points);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar simpleLayout = function (ecModel, api) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var layout = seriesModel.get('layout');\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type !== 'view') {\n            var data = seriesModel.getData();\n\n            var dimensions = [];\n            each$1(coordSys.dimensions, function (coordDim) {\n                dimensions = dimensions.concat(data.mapDimension(coordDim, true));\n            });\n\n            for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {\n                var value = [];\n                var hasValue = false;\n                for (var i = 0; i < dimensions.length; i++) {\n                    var val = data.get(dimensions[i], dataIndex);\n                    if (!isNaN(val)) {\n                        hasValue = true;\n                    }\n                    value.push(val);\n                }\n                if (hasValue) {\n                    data.setItemLayout(dataIndex, coordSys.dataToPoint(value));\n                }\n                else {\n                    // Also {Array.<number>}, not undefined to avoid if...else... statement\n                    data.setItemLayout(dataIndex, [NaN, NaN]);\n                }\n            }\n\n            simpleLayoutEdge(data.graph);\n        }\n        else if (!layout || layout === 'none') {\n            simpleLayout$1(seriesModel);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction circularLayout$1(seriesModel) {\n    var coordSys = seriesModel.coordinateSystem;\n    if (coordSys && coordSys.type !== 'view') {\n        return;\n    }\n\n    var rect = coordSys.getBoundingRect();\n\n    var nodeData = seriesModel.getData();\n    var graph = nodeData.graph;\n\n    var angle = 0;\n    var sum = nodeData.getSum('value');\n    var unitAngle = Math.PI * 2 / (sum || nodeData.count());\n\n    var cx = rect.width / 2 + rect.x;\n    var cy = rect.height / 2 + rect.y;\n\n    var r = Math.min(rect.width, rect.height) / 2;\n\n    graph.eachNode(function (node) {\n        var value = node.getValue('value');\n\n        angle += unitAngle * (sum ? value : 1) / 2;\n\n        node.setLayout([\n            r * Math.cos(angle) + cx,\n            r * Math.sin(angle) + cy\n        ]);\n\n        angle += unitAngle * (sum ? value : 1) / 2;\n    });\n\n    nodeData.setLayout({\n        cx: cx,\n        cy: cy\n    });\n\n    graph.eachEdge(function (edge) {\n        var curveness = edge.getModel().get('lineStyle.curveness') || 0;\n        var p1 = clone$1(edge.node1.getLayout());\n        var p2 = clone$1(edge.node2.getLayout());\n        var cp1;\n        var x12 = (p1[0] + p2[0]) / 2;\n        var y12 = (p1[1] + p2[1]) / 2;\n        if (+curveness) {\n            curveness *= 3;\n            cp1 = [\n                cx * curveness + x12 * (1 - curveness),\n                cy * curveness + y12 * (1 - curveness)\n            ];\n        }\n        edge.setLayout([p1, p2, cp1]);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar circularLayout = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        if (seriesModel.get('layout') === 'circular') {\n            circularLayout$1(seriesModel);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* The layout implementation references to d3.js. The use of\n* the source code of this file is also subject to the terms\n* and consitions of its license (BSD-3Clause, see\n* <echarts/src/licenses/LICENSE-d3>).\n*/\n\nvar scaleAndAdd$2 = scaleAndAdd;\n\n// function adjacentNode(n, e) {\n//     return e.n1 === n ? e.n2 : e.n1;\n// }\n\nfunction forceLayout$1(nodes, edges, opts) {\n    var rect = opts.rect;\n    var width = rect.width;\n    var height = rect.height;\n    var center = [rect.x + width / 2, rect.y + height / 2];\n    // var scale = opts.scale || 1;\n    var gravity = opts.gravity == null ? 0.1 : opts.gravity;\n\n    // for (var i = 0; i < edges.length; i++) {\n    //     var e = edges[i];\n    //     var n1 = e.n1;\n    //     var n2 = e.n2;\n    //     n1.edges = n1.edges || [];\n    //     n2.edges = n2.edges || [];\n    //     n1.edges.push(e);\n    //     n2.edges.push(e);\n    // }\n    // Init position\n    for (var i = 0; i < nodes.length; i++) {\n        var n = nodes[i];\n        if (!n.p) {\n            // Use the position from first adjecent node with defined position\n            // Or use a random position\n            // From d3\n            // if (n.edges) {\n            //     var j = -1;\n            //     while (++j < n.edges.length) {\n            //         var e = n.edges[j];\n            //         var other = adjacentNode(n, e);\n            //         if (other.p) {\n            //             n.p = vec2.clone(other.p);\n            //             break;\n            //         }\n            //     }\n            // }\n            // if (!n.p) {\n                n.p = create(\n                    width * (Math.random() - 0.5) + center[0],\n                    height * (Math.random() - 0.5) + center[1]\n                );\n            // }\n        }\n        n.pp = clone$1(n.p);\n        n.edges = null;\n    }\n\n    // Formula in 'Graph Drawing by Force-directed Placement'\n    // var k = scale * Math.sqrt(width * height / nodes.length);\n    // var k2 = k * k;\n\n    var friction = 0.6;\n\n    return {\n        warmUp: function () {\n            friction = 0.5;\n        },\n\n        setFixed: function (idx) {\n            nodes[idx].fixed = true;\n        },\n\n        setUnfixed: function (idx) {\n            nodes[idx].fixed = false;\n        },\n\n        step: function (cb) {\n            var v12 = [];\n            var nLen = nodes.length;\n            for (var i = 0; i < edges.length; i++) {\n                var e = edges[i];\n                var n1 = e.n1;\n                var n2 = e.n2;\n\n                sub(v12, n2.p, n1.p);\n                var d = len(v12) - e.d;\n                var w = n2.w / (n1.w + n2.w);\n\n                if (isNaN(w)) {\n                    w = 0;\n                }\n\n                normalize(v12, v12);\n\n                !n1.fixed && scaleAndAdd$2(n1.p, n1.p, v12, w * d * friction);\n                !n2.fixed && scaleAndAdd$2(n2.p, n2.p, v12, -(1 - w) * d * friction);\n            }\n            // Gravity\n            for (var i = 0; i < nLen; i++) {\n                var n = nodes[i];\n                if (!n.fixed) {\n                    sub(v12, center, n.p);\n                    // var d = vec2.len(v12);\n                    // vec2.scale(v12, v12, 1 / d);\n                    // var gravityFactor = gravity;\n                    scaleAndAdd$2(n.p, n.p, v12, gravity * friction);\n                }\n            }\n\n            // Repulsive\n            // PENDING\n            for (var i = 0; i < nLen; i++) {\n                var n1 = nodes[i];\n                for (var j = i + 1; j < nLen; j++) {\n                    var n2 = nodes[j];\n                    sub(v12, n2.p, n1.p);\n                    var d = len(v12);\n                    if (d === 0) {\n                        // Random repulse\n                        set(v12, Math.random() - 0.5, Math.random() - 0.5);\n                        d = 1;\n                    }\n                    var repFact = (n1.rep + n2.rep) / d / d;\n                    !n1.fixed && scaleAndAdd$2(n1.pp, n1.pp, v12, repFact);\n                    !n2.fixed && scaleAndAdd$2(n2.pp, n2.pp, v12, -repFact);\n                }\n            }\n            var v = [];\n            for (var i = 0; i < nLen; i++) {\n                var n = nodes[i];\n                if (!n.fixed) {\n                    sub(v, n.p, n.pp);\n                    scaleAndAdd$2(n.p, n.p, v, friction);\n                    copy(n.pp, n.p);\n                }\n            }\n\n            friction = friction * 0.992;\n\n            cb && cb(nodes, edges, friction < 0.01);\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar forceLayout = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (graphSeries) {\n        var coordSys = graphSeries.coordinateSystem;\n        if (coordSys && coordSys.type !== 'view') {\n            return;\n        }\n        if (graphSeries.get('layout') === 'force') {\n            var preservedPoints = graphSeries.preservedPoints || {};\n            var graph = graphSeries.getGraph();\n            var nodeData = graph.data;\n            var edgeData = graph.edgeData;\n            var forceModel = graphSeries.getModel('force');\n            var initLayout = forceModel.get('initLayout');\n            if (graphSeries.preservedPoints) {\n                nodeData.each(function (idx) {\n                    var id = nodeData.getId(idx);\n                    nodeData.setItemLayout(idx, preservedPoints[id] || [NaN, NaN]);\n                });\n            }\n            else if (!initLayout || initLayout === 'none') {\n                simpleLayout$1(graphSeries);\n            }\n            else if (initLayout === 'circular') {\n                circularLayout$1(graphSeries);\n            }\n\n            var nodeDataExtent = nodeData.getDataExtent('value');\n            var edgeDataExtent = edgeData.getDataExtent('value');\n            // var edgeDataExtent = edgeData.getDataExtent('value');\n            var repulsion = forceModel.get('repulsion');\n            var edgeLength = forceModel.get('edgeLength');\n            if (!isArray(repulsion)) {\n                repulsion = [repulsion, repulsion];\n            }\n            if (!isArray(edgeLength)) {\n                edgeLength = [edgeLength, edgeLength];\n            }\n            // Larger value has smaller length\n            edgeLength = [edgeLength[1], edgeLength[0]];\n\n            var nodes = nodeData.mapArray('value', function (value, idx) {\n                var point = nodeData.getItemLayout(idx);\n                var rep = linearMap(value, nodeDataExtent, repulsion);\n                if (isNaN(rep)) {\n                    rep = (repulsion[0] + repulsion[1]) / 2;\n                }\n                return {\n                    w: rep,\n                    rep: rep,\n                    fixed: nodeData.getItemModel(idx).get('fixed'),\n                    p: (!point || isNaN(point[0]) || isNaN(point[1])) ? null : point\n                };\n            });\n            var edges = edgeData.mapArray('value', function (value, idx) {\n                var edge = graph.getEdgeByIndex(idx);\n                var d = linearMap(value, edgeDataExtent, edgeLength);\n                if (isNaN(d)) {\n                    d = (edgeLength[0] + edgeLength[1]) / 2;\n                }\n                return {\n                    n1: nodes[edge.node1.dataIndex],\n                    n2: nodes[edge.node2.dataIndex],\n                    d: d,\n                    curveness: edge.getModel().get('lineStyle.curveness') || 0\n                };\n            });\n\n            var coordSys = graphSeries.coordinateSystem;\n            var rect = coordSys.getBoundingRect();\n            var forceInstance = forceLayout$1(nodes, edges, {\n                rect: rect,\n                gravity: forceModel.get('gravity')\n            });\n            var oldStep = forceInstance.step;\n            forceInstance.step = function (cb) {\n                for (var i = 0, l = nodes.length; i < l; i++) {\n                    if (nodes[i].fixed) {\n                        // Write back to layout instance\n                        copy(nodes[i].p, graph.getNodeByIndex(i).getLayout());\n                    }\n                }\n                oldStep(function (nodes, edges, stopped) {\n                    for (var i = 0, l = nodes.length; i < l; i++) {\n                        if (!nodes[i].fixed) {\n                            graph.getNodeByIndex(i).setLayout(nodes[i].p);\n                        }\n                        preservedPoints[nodeData.getId(i)] = nodes[i].p;\n                    }\n                    for (var i = 0, l = edges.length; i < l; i++) {\n                        var e = edges[i];\n                        var edge = graph.getEdgeByIndex(i);\n                        var p1 = e.n1.p;\n                        var p2 = e.n2.p;\n                        var points = edge.getLayout();\n                        points = points ? points.slice() : [];\n                        points[0] = points[0] || [];\n                        points[1] = points[1] || [];\n                        copy(points[0], p1);\n                        copy(points[1], p2);\n                        if (+e.curveness) {\n                            points[2] = [\n                                (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * e.curveness,\n                                (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * e.curveness\n                            ];\n                        }\n                        edge.setLayout(points);\n                    }\n                    // Update layout\n\n                    cb && cb(stopped);\n                });\n            };\n            graphSeries.forceLayout = forceInstance;\n            graphSeries.preservedPoints = preservedPoints;\n\n            // Step to get the layout\n            forceInstance.step();\n        }\n        else {\n            // Remove prev injected forceLayout instance\n            graphSeries.forceLayout = null;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Where to create the simple view coordinate system\nfunction getViewRect$1(seriesModel, api, aspect) {\n    var option = seriesModel.getBoxLayoutParams();\n    option.aspect = aspect;\n    return getLayoutRect(option, {\n        width: api.getWidth(),\n        height: api.getHeight()\n    });\n}\n\nvar createView = function (ecModel, api) {\n    var viewList = [];\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var coordSysType = seriesModel.get('coordinateSystem');\n        if (!coordSysType || coordSysType === 'view') {\n\n            var data = seriesModel.getData();\n            var positions = data.mapArray(function (idx) {\n                var itemModel = data.getItemModel(idx);\n                return [+itemModel.get('x'), +itemModel.get('y')];\n            });\n\n            var min = [];\n            var max = [];\n\n            fromPoints(positions, min, max);\n\n            // If width or height is 0\n            if (max[0] - min[0] === 0) {\n                max[0] += 1;\n                min[0] -= 1;\n            }\n            if (max[1] - min[1] === 0) {\n                max[1] += 1;\n                min[1] -= 1;\n            }\n            var aspect = (max[0] - min[0]) / (max[1] - min[1]);\n            // FIXME If get view rect after data processed?\n            var viewRect = getViewRect$1(seriesModel, api, aspect);\n            // Position may be NaN, use view rect instead\n            if (isNaN(aspect)) {\n                min = [viewRect.x, viewRect.y];\n                max = [viewRect.x + viewRect.width, viewRect.y + viewRect.height];\n            }\n\n            var bbWidth = max[0] - min[0];\n            var bbHeight = max[1] - min[1];\n\n            var viewWidth = viewRect.width;\n            var viewHeight = viewRect.height;\n\n            var viewCoordSys = seriesModel.coordinateSystem = new View();\n            viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');\n\n            viewCoordSys.setBoundingRect(\n                min[0], min[1], bbWidth, bbHeight\n            );\n            viewCoordSys.setViewRect(\n                viewRect.x, viewRect.y, viewWidth, viewHeight\n            );\n\n            // Update roam info\n            viewCoordSys.setCenter(seriesModel.get('center'));\n            viewCoordSys.setZoom(seriesModel.get('zoom'));\n\n            viewList.push(viewCoordSys);\n        }\n    });\n\n    return viewList;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor(categoryFilter);\n\nregisterVisual(visualSymbol('graph', 'circle', null));\nregisterVisual(categoryVisual);\nregisterVisual(edgeVisual);\n\nregisterLayout(simpleLayout);\nregisterLayout(circularLayout);\nregisterLayout(forceLayout);\n\n// Graph view coordinate system\nregisterCoordinateSystem('graphView', {\n    create: createView\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GaugeSeries = SeriesModel.extend({\n\n    type: 'series.gauge',\n\n    getInitialData: function (option, ecModel) {\n        var dataOpt = option.data || [];\n        if (!isArray(dataOpt)) {\n            dataOpt = [dataOpt];\n        }\n        option.data = dataOpt;\n        return createListSimply(this, ['value']);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        legendHoverLink: true,\n        radius: '75%',\n        startAngle: 225,\n        endAngle: -45,\n        clockwise: true,\n        // 最小值\n        min: 0,\n        // 最大值\n        max: 100,\n        // 分割段数，默认为10\n        splitNumber: 10,\n        // 坐标轴线\n        axisLine: {\n            // 默认显示，属性show控制显示与否\n            show: true,\n            lineStyle: {       // 属性lineStyle控制线条样式\n                color: [[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']],\n                width: 30\n            }\n        },\n        // 分隔线\n        splitLine: {\n            // 默认显示，属性show控制显示与否\n            show: true,\n            // 属性length控制线长\n            length: 30,\n            // 属性lineStyle（详见lineStyle）控制线条样式\n            lineStyle: {\n                color: '#eee',\n                width: 2,\n                type: 'solid'\n            }\n        },\n        // 坐标轴小标记\n        axisTick: {\n            // 属性show控制显示与否，默认不显示\n            show: true,\n            // 每份split细分多少段\n            splitNumber: 5,\n            // 属性length控制线长\n            length: 8,\n            // 属性lineStyle控制线条样式\n            lineStyle: {\n                color: '#eee',\n                width: 1,\n                type: 'solid'\n            }\n        },\n        axisLabel: {\n            show: true,\n            distance: 5,\n            // formatter: null,\n            color: 'auto'\n        },\n        pointer: {\n            show: true,\n            length: '80%',\n            width: 8\n        },\n        itemStyle: {\n            color: 'auto'\n        },\n        title: {\n            show: true,\n            // x, y，单位px\n            offsetCenter: [0, '-40%'],\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: '#333',\n            fontSize: 15\n        },\n        detail: {\n            show: true,\n            backgroundColor: 'rgba(0,0,0,0)',\n            borderWidth: 0,\n            borderColor: '#ccc',\n            width: 100,\n            height: null, // self-adaption\n            padding: [5, 10],\n            // x, y，单位px\n            offsetCenter: [0, '40%'],\n            // formatter: null,\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: 'auto',\n            fontSize: 30\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PointerPath = Path.extend({\n\n    type: 'echartsGaugePointer',\n\n    shape: {\n        angle: 0,\n\n        width: 10,\n\n        r: 10,\n\n        x: 0,\n\n        y: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var mathCos = Math.cos;\n        var mathSin = Math.sin;\n\n        var r = shape.r;\n        var width = shape.width;\n        var angle = shape.angle;\n        var x = shape.x - mathCos(angle) * width * (width >= r / 3 ? 1 : 2);\n        var y = shape.y - mathSin(angle) * width * (width >= r / 3 ? 1 : 2);\n\n        angle = shape.angle - Math.PI / 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(\n            shape.x + mathCos(angle) * width,\n            shape.y + mathSin(angle) * width\n        );\n        ctx.lineTo(\n            shape.x + mathCos(shape.angle) * r,\n            shape.y + mathSin(shape.angle) * r\n        );\n        ctx.lineTo(\n            shape.x - mathCos(angle) * width,\n            shape.y - mathSin(angle) * width\n        );\n        ctx.lineTo(x, y);\n        return;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction parsePosition(seriesModel, api) {\n    var center = seriesModel.get('center');\n    var width = api.getWidth();\n    var height = api.getHeight();\n    var size = Math.min(width, height);\n    var cx = parsePercent$1(center[0], api.getWidth());\n    var cy = parsePercent$1(center[1], api.getHeight());\n    var r = parsePercent$1(seriesModel.get('radius'), size / 2);\n\n    return {\n        cx: cx,\n        cy: cy,\n        r: r\n    };\n}\n\nfunction formatLabel(label, labelFormatter) {\n    if (labelFormatter) {\n        if (typeof labelFormatter === 'string') {\n            label = labelFormatter.replace('{value}', label != null ? label : '');\n        }\n        else if (typeof labelFormatter === 'function') {\n            label = labelFormatter(label);\n        }\n    }\n\n    return label;\n}\n\nvar PI2$5 = Math.PI * 2;\n\nvar GaugeView = Chart.extend({\n\n    type: 'gauge',\n\n    render: function (seriesModel, ecModel, api) {\n\n        this.group.removeAll();\n\n        var colorList = seriesModel.get('axisLine.lineStyle.color');\n        var posInfo = parsePosition(seriesModel, api);\n\n        this._renderMain(\n            seriesModel, ecModel, api, colorList, posInfo\n        );\n    },\n\n    dispose: function () {},\n\n    _renderMain: function (seriesModel, ecModel, api, colorList, posInfo) {\n        var group = this.group;\n\n        var axisLineModel = seriesModel.getModel('axisLine');\n        var lineStyleModel = axisLineModel.getModel('lineStyle');\n\n        var clockwise = seriesModel.get('clockwise');\n        var startAngle = -seriesModel.get('startAngle') / 180 * Math.PI;\n        var endAngle = -seriesModel.get('endAngle') / 180 * Math.PI;\n\n        var angleRangeSpan = (endAngle - startAngle) % PI2$5;\n\n        var prevEndAngle = startAngle;\n        var axisLineWidth = lineStyleModel.get('width');\n\n        for (var i = 0; i < colorList.length; i++) {\n            // Clamp\n            var percent = Math.min(Math.max(colorList[i][0], 0), 1);\n            var endAngle = startAngle + angleRangeSpan * percent;\n            var sector = new Sector({\n                shape: {\n                    startAngle: prevEndAngle,\n                    endAngle: endAngle,\n                    cx: posInfo.cx,\n                    cy: posInfo.cy,\n                    clockwise: clockwise,\n                    r0: posInfo.r - axisLineWidth,\n                    r: posInfo.r\n                },\n                silent: true\n            });\n\n            sector.setStyle({\n                fill: colorList[i][1]\n            });\n\n            sector.setStyle(lineStyleModel.getLineStyle(\n                // Because we use sector to simulate arc\n                // so the properties for stroking are useless\n                ['color', 'borderWidth', 'borderColor']\n            ));\n\n            group.add(sector);\n\n            prevEndAngle = endAngle;\n        }\n\n        var getColor = function (percent) {\n            // Less than 0\n            if (percent <= 0) {\n                return colorList[0][1];\n            }\n            for (var i = 0; i < colorList.length; i++) {\n                if (colorList[i][0] >= percent\n                    && (i === 0 ? 0 : colorList[i - 1][0]) < percent\n                ) {\n                    return colorList[i][1];\n                }\n            }\n            // More than 1\n            return colorList[i - 1][1];\n        };\n\n        if (!clockwise) {\n            var tmp = startAngle;\n            startAngle = endAngle;\n            endAngle = tmp;\n        }\n\n        this._renderTicks(\n            seriesModel, ecModel, api, getColor, posInfo,\n            startAngle, endAngle, clockwise\n        );\n\n        this._renderPointer(\n            seriesModel, ecModel, api, getColor, posInfo,\n            startAngle, endAngle, clockwise\n        );\n\n        this._renderTitle(\n            seriesModel, ecModel, api, getColor, posInfo\n        );\n        this._renderDetail(\n            seriesModel, ecModel, api, getColor, posInfo\n        );\n    },\n\n    _renderTicks: function (\n        seriesModel, ecModel, api, getColor, posInfo,\n        startAngle, endAngle, clockwise\n    ) {\n        var group = this.group;\n        var cx = posInfo.cx;\n        var cy = posInfo.cy;\n        var r = posInfo.r;\n\n        var minVal = +seriesModel.get('min');\n        var maxVal = +seriesModel.get('max');\n\n        var splitLineModel = seriesModel.getModel('splitLine');\n        var tickModel = seriesModel.getModel('axisTick');\n        var labelModel = seriesModel.getModel('axisLabel');\n\n        var splitNumber = seriesModel.get('splitNumber');\n        var subSplitNumber = tickModel.get('splitNumber');\n\n        var splitLineLen = parsePercent$1(\n            splitLineModel.get('length'), r\n        );\n        var tickLen = parsePercent$1(\n            tickModel.get('length'), r\n        );\n\n        var angle = startAngle;\n        var step = (endAngle - startAngle) / splitNumber;\n        var subStep = step / subSplitNumber;\n\n        var splitLineStyle = splitLineModel.getModel('lineStyle').getLineStyle();\n        var tickLineStyle = tickModel.getModel('lineStyle').getLineStyle();\n\n        for (var i = 0; i <= splitNumber; i++) {\n            var unitX = Math.cos(angle);\n            var unitY = Math.sin(angle);\n            // Split line\n            if (splitLineModel.get('show')) {\n                var splitLine = new Line({\n                    shape: {\n                        x1: unitX * r + cx,\n                        y1: unitY * r + cy,\n                        x2: unitX * (r - splitLineLen) + cx,\n                        y2: unitY * (r - splitLineLen) + cy\n                    },\n                    style: splitLineStyle,\n                    silent: true\n                });\n                if (splitLineStyle.stroke === 'auto') {\n                    splitLine.setStyle({\n                        stroke: getColor(i / splitNumber)\n                    });\n                }\n\n                group.add(splitLine);\n            }\n\n            // Label\n            if (labelModel.get('show')) {\n                var label = formatLabel(\n                    round$2(i / splitNumber * (maxVal - minVal) + minVal),\n                    labelModel.get('formatter')\n                );\n                var distance = labelModel.get('distance');\n                var autoColor = getColor(i / splitNumber);\n\n                group.add(new Text({\n                    style: setTextStyle({}, labelModel, {\n                        text: label,\n                        x: unitX * (r - splitLineLen - distance) + cx,\n                        y: unitY * (r - splitLineLen - distance) + cy,\n                        textVerticalAlign: unitY < -0.4 ? 'top' : (unitY > 0.4 ? 'bottom' : 'middle'),\n                        textAlign: unitX < -0.4 ? 'left' : (unitX > 0.4 ? 'right' : 'center')\n                    }, {autoColor: autoColor}),\n                    silent: true\n                }));\n            }\n\n            // Axis tick\n            if (tickModel.get('show') && i !== splitNumber) {\n                for (var j = 0; j <= subSplitNumber; j++) {\n                    var unitX = Math.cos(angle);\n                    var unitY = Math.sin(angle);\n                    var tickLine = new Line({\n                        shape: {\n                            x1: unitX * r + cx,\n                            y1: unitY * r + cy,\n                            x2: unitX * (r - tickLen) + cx,\n                            y2: unitY * (r - tickLen) + cy\n                        },\n                        silent: true,\n                        style: tickLineStyle\n                    });\n\n                    if (tickLineStyle.stroke === 'auto') {\n                        tickLine.setStyle({\n                            stroke: getColor((i + j / subSplitNumber) / splitNumber)\n                        });\n                    }\n\n                    group.add(tickLine);\n                    angle += subStep;\n                }\n                angle -= subStep;\n            }\n            else {\n                angle += step;\n            }\n        }\n    },\n\n    _renderPointer: function (\n        seriesModel, ecModel, api, getColor, posInfo,\n        startAngle, endAngle, clockwise\n    ) {\n\n        var group = this.group;\n        var oldData = this._data;\n\n        if (!seriesModel.get('pointer.show')) {\n            // Remove old element\n            oldData && oldData.eachItemGraphicEl(function (el) {\n                group.remove(el);\n            });\n            return;\n        }\n\n        var valueExtent = [+seriesModel.get('min'), +seriesModel.get('max')];\n        var angleExtent = [startAngle, endAngle];\n\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var pointer = new PointerPath({\n                    shape: {\n                        angle: startAngle\n                    }\n                });\n\n                initProps(pointer, {\n                    shape: {\n                        angle: linearMap(data.get(valueDim, idx), valueExtent, angleExtent, true)\n                    }\n                }, seriesModel);\n\n                group.add(pointer);\n                data.setItemGraphicEl(idx, pointer);\n            })\n            .update(function (newIdx, oldIdx) {\n                var pointer = oldData.getItemGraphicEl(oldIdx);\n\n                updateProps(pointer, {\n                    shape: {\n                        angle: linearMap(data.get(valueDim, newIdx), valueExtent, angleExtent, true)\n                    }\n                }, seriesModel);\n\n                group.add(pointer);\n                data.setItemGraphicEl(newIdx, pointer);\n            })\n            .remove(function (idx) {\n                var pointer = oldData.getItemGraphicEl(idx);\n                group.remove(pointer);\n            })\n            .execute();\n\n        data.eachItemGraphicEl(function (pointer, idx) {\n            var itemModel = data.getItemModel(idx);\n            var pointerModel = itemModel.getModel('pointer');\n\n            pointer.setShape({\n                x: posInfo.cx,\n                y: posInfo.cy,\n                width: parsePercent$1(\n                    pointerModel.get('width'), posInfo.r\n                ),\n                r: parsePercent$1(pointerModel.get('length'), posInfo.r)\n            });\n\n            pointer.useStyle(itemModel.getModel('itemStyle').getItemStyle());\n\n            if (pointer.style.fill === 'auto') {\n                pointer.setStyle('fill', getColor(\n                    linearMap(data.get(valueDim, idx), valueExtent, [0, 1], true)\n                ));\n            }\n\n            setHoverStyle(\n                pointer, itemModel.getModel('emphasis.itemStyle').getItemStyle()\n            );\n        });\n\n        this._data = data;\n    },\n\n    _renderTitle: function (\n        seriesModel, ecModel, api, getColor, posInfo\n    ) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n        var titleModel = seriesModel.getModel('title');\n        if (titleModel.get('show')) {\n            var offsetCenter = titleModel.get('offsetCenter');\n            var x = posInfo.cx + parsePercent$1(offsetCenter[0], posInfo.r);\n            var y = posInfo.cy + parsePercent$1(offsetCenter[1], posInfo.r);\n\n            var minVal = +seriesModel.get('min');\n            var maxVal = +seriesModel.get('max');\n            var value = seriesModel.getData().get(valueDim, 0);\n            var autoColor = getColor(\n                linearMap(value, [minVal, maxVal], [0, 1], true)\n            );\n\n            this.group.add(new Text({\n                silent: true,\n                style: setTextStyle({}, titleModel, {\n                    x: x,\n                    y: y,\n                    // FIXME First data name ?\n                    text: data.getName(0),\n                    textAlign: 'center',\n                    textVerticalAlign: 'middle'\n                }, {autoColor: autoColor, forceRich: true})\n            }));\n        }\n    },\n\n    _renderDetail: function (\n        seriesModel, ecModel, api, getColor, posInfo\n    ) {\n        var detailModel = seriesModel.getModel('detail');\n        var minVal = +seriesModel.get('min');\n        var maxVal = +seriesModel.get('max');\n        if (detailModel.get('show')) {\n            var offsetCenter = detailModel.get('offsetCenter');\n            var x = posInfo.cx + parsePercent$1(offsetCenter[0], posInfo.r);\n            var y = posInfo.cy + parsePercent$1(offsetCenter[1], posInfo.r);\n            var width = parsePercent$1(detailModel.get('width'), posInfo.r);\n            var height = parsePercent$1(detailModel.get('height'), posInfo.r);\n            var data = seriesModel.getData();\n            var value = data.get(data.mapDimension('value'), 0);\n            var autoColor = getColor(\n                linearMap(value, [minVal, maxVal], [0, 1], true)\n            );\n\n            this.group.add(new Text({\n                silent: true,\n                style: setTextStyle({}, detailModel, {\n                    x: x,\n                    y: y,\n                    text: formatLabel(\n                        // FIXME First data name ?\n                        value, detailModel.get('formatter')\n                    ),\n                    textWidth: isNaN(width) ? null : width,\n                    textHeight: isNaN(height) ? null : height,\n                    textAlign: 'center',\n                    textVerticalAlign: 'middle'\n                }, {autoColor: autoColor, forceRich: true})\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar FunnelSeries = extendSeriesModel({\n\n    type: 'series.funnel',\n\n    init: function (option) {\n        FunnelSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n        // Extend labelLine emphasis\n        this._defaultLabelLine(option);\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = FunnelSeries.superCall(this, 'getDataParams', dataIndex);\n        var valueDim = data.mapDimension('value');\n        var sum = data.getSum(valueDim);\n        // Percent is 0 if sum is 0\n        params.percent = !sum ? 0 : +(data.get(valueDim, dataIndex) / sum * 100).toFixed(2);\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        legendHoverLink: true,\n        left: 80,\n        top: 60,\n        right: 80,\n        bottom: 60,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n\n        // 默认取数据最小最大值\n        // min: 0,\n        // max: 100,\n        minSize: '0%',\n        maxSize: '100%',\n        sort: 'descending', // 'ascending', 'descending'\n        gap: 0,\n        funnelAlign: 'center',\n        label: {\n            show: true,\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n        },\n        labelLine: {\n            show: true,\n            length: 20,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            // color: 各异,\n            borderColor: '#fff',\n            borderWidth: 1\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction FunnelPiece(data, idx) {\n\n    Group.call(this);\n\n    var polygon = new Polygon();\n    var labelLine = new Polyline();\n    var text = new Text();\n    this.add(polygon);\n    this.add(labelLine);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        labelLine.ignore = labelLine.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        labelLine.ignore = labelLine.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar funnelPieceProto = FunnelPiece.prototype;\n\nvar opacityAccessPath = ['itemStyle', 'opacity'];\nfunnelPieceProto.updateData = function (data, idx, firstCreate) {\n\n    var polygon = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var opacity = data.getItemModel(idx).get(opacityAccessPath);\n    opacity = opacity == null ? 1 : opacity;\n\n    // Reset style\n    polygon.useStyle({});\n\n    if (firstCreate) {\n        polygon.setShape({\n            points: layout.points\n        });\n        polygon.setStyle({opacity: 0});\n        initProps(polygon, {\n            style: {\n                opacity: opacity\n            }\n        }, seriesModel, idx);\n    }\n    else {\n        updateProps(polygon, {\n            style: {\n                opacity: opacity\n            },\n            shape: {\n                points: layout.points\n            }\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    polygon.setStyle(\n        defaults(\n            {\n                lineJoin: 'round',\n                fill: visualColor\n            },\n            itemStyleModel.getItemStyle(['opacity'])\n        )\n    );\n    polygon.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle();\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\nfunnelPieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || labelLayout.linePoints\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n};\n\ninherits(FunnelPiece, Group);\n\n\nvar FunnelView = Chart.extend({\n\n    type: 'funnel',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var group = this.group;\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var funnelPiece = new FunnelPiece(data, idx);\n\n                data.setItemGraphicEl(idx, funnelPiece);\n\n                group.add(funnelPiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    remove: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getViewRect$2(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\nfunction getSortedIndices(data, sort) {\n    var valueDim = data.mapDimension('value');\n    var valueArr = data.mapArray(valueDim, function (val) {\n        return val;\n    });\n    var indices = [];\n    var isAscending = sort === 'ascending';\n    for (var i = 0, len = data.count(); i < len; i++) {\n        indices[i] = i;\n    }\n\n    // Add custom sortable function & none sortable opetion by \"options.sort\"\n    if (typeof sort === 'function') {\n        indices.sort(sort);\n    }\n    else if (sort !== 'none') {\n        indices.sort(function (a, b) {\n            return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a];\n        });\n    }\n    return indices;\n}\n\nfunction labelLayout$1(data) {\n    data.each(function (idx) {\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        var labelPosition = labelModel.get('position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n\n        var layout = data.getItemLayout(idx);\n        var points = layout.points;\n\n        var isLabelInside = labelPosition === 'inner'\n            || labelPosition === 'inside' || labelPosition === 'center';\n\n        var textAlign;\n        var textX;\n        var textY;\n        var linePoints;\n\n        if (isLabelInside) {\n            textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4;\n            textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4;\n            textAlign = 'center';\n            linePoints = [\n                [textX, textY], [textX, textY]\n            ];\n        }\n        else {\n            var x1;\n            var y1;\n            var x2;\n            var labelLineLen = labelLineModel.get('length');\n            if (labelPosition === 'left') {\n                // Left side\n                x1 = (points[3][0] + points[0][0]) / 2;\n                y1 = (points[3][1] + points[0][1]) / 2;\n                x2 = x1 - labelLineLen;\n                textX = x2 - 5;\n                textAlign = 'right';\n            }\n            else {\n                // Right side\n                x1 = (points[1][0] + points[2][0]) / 2;\n                y1 = (points[1][1] + points[2][1]) / 2;\n                x2 = x1 + labelLineLen;\n                textX = x2 + 5;\n                textAlign = 'left';\n            }\n            var y2 = y1;\n\n            linePoints = [[x1, y1], [x2, y2]];\n            textY = y2;\n        }\n\n        layout.label = {\n            linePoints: linePoints,\n            x: textX,\n            y: textY,\n            verticalAlign: 'middle',\n            textAlign: textAlign,\n            inside: isLabelInside\n        };\n    });\n}\n\nvar funnelLayout = function (ecModel, api, payload) {\n    ecModel.eachSeriesByType('funnel', function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n        var sort = seriesModel.get('sort');\n        var viewRect = getViewRect$2(seriesModel, api);\n        var indices = getSortedIndices(data, sort);\n\n        var sizeExtent = [\n            parsePercent$1(seriesModel.get('minSize'), viewRect.width),\n            parsePercent$1(seriesModel.get('maxSize'), viewRect.width)\n        ];\n        var dataExtent = data.getDataExtent(valueDim);\n        var min = seriesModel.get('min');\n        var max = seriesModel.get('max');\n        if (min == null) {\n            min = Math.min(dataExtent[0], 0);\n        }\n        if (max == null) {\n            max = dataExtent[1];\n        }\n\n        var funnelAlign = seriesModel.get('funnelAlign');\n        var gap = seriesModel.get('gap');\n        var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count();\n\n        var y = viewRect.y;\n\n        var getLinePoints = function (idx, offY) {\n            // End point index is data.count() and we assign it 0\n            var val = data.get(valueDim, idx) || 0;\n            var itemWidth = linearMap(val, [min, max], sizeExtent, true);\n            var x0;\n            switch (funnelAlign) {\n                case 'left':\n                    x0 = viewRect.x;\n                    break;\n                case 'center':\n                    x0 = viewRect.x + (viewRect.width - itemWidth) / 2;\n                    break;\n                case 'right':\n                    x0 = viewRect.x + viewRect.width - itemWidth;\n                    break;\n            }\n            return [\n                [x0, offY],\n                [x0 + itemWidth, offY]\n            ];\n        };\n\n        if (sort === 'ascending') {\n            // From bottom to top\n            itemHeight = -itemHeight;\n            gap = -gap;\n            y += viewRect.height;\n            indices = indices.reverse();\n        }\n\n        for (var i = 0; i < indices.length; i++) {\n            var idx = indices[i];\n            var nextIdx = indices[i + 1];\n\n            var itemModel = data.getItemModel(idx);\n            var height = itemModel.get('itemStyle.height');\n            if (height == null) {\n                height = itemHeight;\n            }\n            else {\n                height = parsePercent$1(height, viewRect.height);\n                if (sort === 'ascending') {\n                    height = -height;\n                }\n            }\n\n            var start = getLinePoints(idx, y);\n            var end = getLinePoints(nextIdx, y + height);\n\n            y += height + gap;\n\n            data.setItemLayout(idx, {\n                points: start.concat(end.slice().reverse())\n            });\n        }\n\n        labelLayout$1(data);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(dataColor('funnel'));\nregisterLayout(funnelLayout);\nregisterProcessor(dataFilter('funnel'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar parallelPreprocessor = function (option) {\n    createParallelIfNeeded(option);\n    mergeAxisOptionFromParallel(option);\n};\n\n/**\n * Create a parallel coordinate if not exists.\n * @inner\n */\nfunction createParallelIfNeeded(option) {\n    if (option.parallel) {\n        return;\n    }\n\n    var hasParallelSeries = false;\n\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'parallel') {\n            hasParallelSeries = true;\n        }\n    });\n\n    if (hasParallelSeries) {\n        option.parallel = [{}];\n    }\n}\n\n/**\n * Merge aixs definition from parallel option (if exists) to axis option.\n * @inner\n */\nfunction mergeAxisOptionFromParallel(option) {\n    var axes = normalizeToArray(option.parallelAxis);\n\n    each$1(axes, function (axisOption) {\n        if (!isObject$1(axisOption)) {\n            return;\n        }\n\n        var parallelIndex = axisOption.parallelIndex || 0;\n        var parallelOption = normalizeToArray(option.parallel)[parallelIndex];\n\n        if (parallelOption && parallelOption.parallelAxisDefault) {\n            merge(axisOption, parallelOption.parallelAxisDefault, false);\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor module:echarts/coord/parallel/ParallelAxis\n * @extends {module:echarts/coord/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n */\nvar ParallelAxis = function (dim, scale, coordExtent, axisType, axisIndex) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.axisIndex = axisIndex;\n};\n\nParallelAxis.prototype = {\n\n    constructor: ParallelAxis,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/parallel/AxisModel}\n     */\n    model: null,\n\n    /**\n     * @override\n     */\n    isHorizontal: function () {\n        return this.coordinateSystem.getModel().get('layout') !== 'horizontal';\n    }\n\n};\n\ninherits(ParallelAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Calculate slider move result.\n * Usage:\n * (1) If both handle0 and handle1 are needed to be moved, set minSpan the same as\n * maxSpan and the same as `Math.abs(handleEnd[1] - handleEnds[0])`.\n * (2) If handle0 is forbidden to cross handle1, set minSpan as `0`.\n *\n * @param {number} delta Move length.\n * @param {Array.<number>} handleEnds handleEnds[0] can be bigger then handleEnds[1].\n *              handleEnds will be modified in this method.\n * @param {Array.<number>} extent handleEnds is restricted by extent.\n *              extent[0] should less or equals than extent[1].\n * @param {number|string} handleIndex Can be 'all', means that both move the two handleEnds,\n *              where the input minSpan and maxSpan will not work.\n * @param {number} [minSpan] The range of dataZoom can not be smaller than that.\n *              If not set, handle0 and cross handle1. If set as a non-negative\n *              number (including `0`), handles will push each other when reaching\n *              the minSpan.\n * @param {number} [maxSpan] The range of dataZoom can not be larger than that.\n * @return {Array.<number>} The input handleEnds.\n */\nvar sliderMove = function (delta, handleEnds, extent, handleIndex, minSpan, maxSpan) {\n    // Normalize firstly.\n    handleEnds[0] = restrict$1(handleEnds[0], extent);\n    handleEnds[1] = restrict$1(handleEnds[1], extent);\n\n    delta = delta || 0;\n\n    var extentSpan = extent[1] - extent[0];\n\n    // Notice maxSpan and minSpan can be null/undefined.\n    if (minSpan != null) {\n        minSpan = restrict$1(minSpan, [0, extentSpan]);\n    }\n    if (maxSpan != null) {\n        maxSpan = Math.max(maxSpan, minSpan != null ? minSpan : 0);\n    }\n    if (handleIndex === 'all') {\n        minSpan = maxSpan = Math.abs(handleEnds[1] - handleEnds[0]);\n        handleIndex = 0;\n    }\n\n    var originalDistSign = getSpanSign(handleEnds, handleIndex);\n\n    handleEnds[handleIndex] += delta;\n\n    // Restrict in extent.\n    var extentMinSpan = minSpan || 0;\n    var realExtent = extent.slice();\n    originalDistSign.sign < 0 ? (realExtent[0] += extentMinSpan) : (realExtent[1] -= extentMinSpan);\n    handleEnds[handleIndex] = restrict$1(handleEnds[handleIndex], realExtent);\n\n    // Expand span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (minSpan != null && (\n        currDistSign.sign !== originalDistSign.sign || currDistSign.span < minSpan\n    )) {\n        // If minSpan exists, 'cross' is forbinden.\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + originalDistSign.sign * minSpan;\n    }\n\n    // Shrink span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (maxSpan != null && currDistSign.span > maxSpan) {\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + currDistSign.sign * maxSpan;\n    }\n\n    return handleEnds;\n};\n\nfunction getSpanSign(handleEnds, handleIndex) {\n    var dist = handleEnds[handleIndex] - handleEnds[1 - handleIndex];\n    // If `handleEnds[0] === handleEnds[1]`, always believe that handleEnd[0]\n    // is at left of handleEnds[1] for non-cross case.\n    return {span: Math.abs(dist), sign: dist > 0 ? -1 : dist < 0 ? 1 : handleIndex ? -1 : 1};\n}\n\nfunction restrict$1(value, extend) {\n    return Math.min(extend[1], Math.max(extend[0], value));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parallel Coordinates\n * <https://en.wikipedia.org/wiki/Parallel_coordinates>\n */\n\nvar each$11 = each$1;\nvar mathMin$5 = Math.min;\nvar mathMax$5 = Math.max;\nvar mathFloor$2 = Math.floor;\nvar mathCeil$2 = Math.ceil;\nvar round$3 = round$2;\n\nvar PI$3 = Math.PI;\n\nfunction Parallel(parallelModel, ecModel, api) {\n\n    /**\n     * key: dimension\n     * @type {Object.<string, module:echarts/coord/parallel/Axis>}\n     * @private\n     */\n    this._axesMap = createHashMap();\n\n    /**\n     * key: dimension\n     * value: {position: [], rotation, }\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._axesLayout = {};\n\n    /**\n     * Always follow axis order.\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    this.dimensions = parallelModel.dimensions;\n\n    /**\n     * @type {module:zrender/core/BoundingRect}\n     */\n    this._rect;\n\n    /**\n     * @type {module:echarts/coord/parallel/ParallelModel}\n     */\n    this._model = parallelModel;\n\n    this._init(parallelModel, ecModel, api);\n}\n\nParallel.prototype = {\n\n    type: 'parallel',\n\n    constructor: Parallel,\n\n    /**\n     * Initialize cartesian coordinate systems\n     * @private\n     */\n    _init: function (parallelModel, ecModel, api) {\n\n        var dimensions = parallelModel.dimensions;\n        var parallelAxisIndex = parallelModel.parallelAxisIndex;\n\n        each$11(dimensions, function (dim, idx) {\n\n            var axisIndex = parallelAxisIndex[idx];\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n\n            var axis = this._axesMap.set(dim, new ParallelAxis(\n                dim,\n                createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisIndex\n            ));\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Injection\n            axisModel.axis = axis;\n            axis.model = axisModel;\n            axis.coordinateSystem = axisModel.coordinateSystem = this;\n\n        }, this);\n    },\n\n    /**\n     * Update axis scale after data processed\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    update: function (ecModel, api) {\n        this._updateAxesFromSeries(this._model, ecModel);\n    },\n\n    /**\n     * @override\n     */\n    containPoint: function (point) {\n        var layoutInfo = this._makeLayoutInfo();\n        var axisBase = layoutInfo.axisBase;\n        var layoutBase = layoutInfo.layoutBase;\n        var pixelDimIndex = layoutInfo.pixelDimIndex;\n        var pAxis = point[1 - pixelDimIndex];\n        var pLayout = point[pixelDimIndex];\n\n        return pAxis >= axisBase\n            && pAxis <= axisBase + layoutInfo.axisLength\n            && pLayout >= layoutBase\n            && pLayout <= layoutBase + layoutInfo.layoutLength;\n    },\n\n    getModel: function () {\n        return this._model;\n    },\n\n    /**\n     * Update properties from series\n     * @private\n     */\n    _updateAxesFromSeries: function (parallelModel, ecModel) {\n        ecModel.eachSeries(function (seriesModel) {\n\n            if (!parallelModel.contains(seriesModel, ecModel)) {\n                return;\n            }\n\n            var data = seriesModel.getData();\n\n            each$11(this.dimensions, function (dim) {\n                var axis = this._axesMap.get(dim);\n                axis.scale.unionExtentFromData(data, data.mapDimension(dim));\n                niceScaleExtent(axis.scale, axis.model);\n            }, this);\n        }, this);\n    },\n\n    /**\n     * Resize the parallel coordinate system.\n     * @param {module:echarts/coord/parallel/ParallelModel} parallelModel\n     * @param {module:echarts/ExtensionAPI} api\n     */\n    resize: function (parallelModel, api) {\n        this._rect = getLayoutRect(\n            parallelModel.getBoxLayoutParams(),\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        this._layoutAxes();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @private\n     */\n    _makeLayoutInfo: function () {\n        var parallelModel = this._model;\n        var rect = this._rect;\n        var xy = ['x', 'y'];\n        var wh = ['width', 'height'];\n        var layout = parallelModel.get('layout');\n        var pixelDimIndex = layout === 'horizontal' ? 0 : 1;\n        var layoutLength = rect[wh[pixelDimIndex]];\n        var layoutExtent = [0, layoutLength];\n        var axisCount = this.dimensions.length;\n\n        var axisExpandWidth = restrict(parallelModel.get('axisExpandWidth'), layoutExtent);\n        var axisExpandCount = restrict(parallelModel.get('axisExpandCount') || 0, [0, axisCount]);\n        var axisExpandable = parallelModel.get('axisExpandable')\n            && axisCount > 3\n            && axisCount > axisExpandCount\n            && axisExpandCount > 1\n            && axisExpandWidth > 0\n            && layoutLength > 0;\n\n        // `axisExpandWindow` is According to the coordinates of [0, axisExpandLength],\n        // for sake of consider the case that axisCollapseWidth is 0 (when screen is narrow),\n        // where collapsed axes should be overlapped.\n        var axisExpandWindow = parallelModel.get('axisExpandWindow');\n        var winSize;\n        if (!axisExpandWindow) {\n            winSize = restrict(axisExpandWidth * (axisExpandCount - 1), layoutExtent);\n            var axisExpandCenter = parallelModel.get('axisExpandCenter') || mathFloor$2(axisCount / 2);\n            axisExpandWindow = [axisExpandWidth * axisExpandCenter - winSize / 2];\n            axisExpandWindow[1] = axisExpandWindow[0] + winSize;\n        }\n        else {\n                winSize = restrict(axisExpandWindow[1] - axisExpandWindow[0], layoutExtent);\n                axisExpandWindow[1] = axisExpandWindow[0] + winSize;\n        }\n\n        var axisCollapseWidth = (layoutLength - winSize) / (axisCount - axisExpandCount);\n        // Avoid axisCollapseWidth is too small.\n        axisCollapseWidth < 3 && (axisCollapseWidth = 0);\n\n        // Find the first and last indices > ewin[0] and < ewin[1].\n        var winInnerIndices = [\n            mathFloor$2(round$3(axisExpandWindow[0] / axisExpandWidth, 1)) + 1,\n            mathCeil$2(round$3(axisExpandWindow[1] / axisExpandWidth, 1)) - 1\n        ];\n\n        // Pos in ec coordinates.\n        var axisExpandWindow0Pos = axisCollapseWidth / axisExpandWidth * axisExpandWindow[0];\n\n        return {\n            layout: layout,\n            pixelDimIndex: pixelDimIndex,\n            layoutBase: rect[xy[pixelDimIndex]],\n            layoutLength: layoutLength,\n            axisBase: rect[xy[1 - pixelDimIndex]],\n            axisLength: rect[wh[1 - pixelDimIndex]],\n            axisExpandable: axisExpandable,\n            axisExpandWidth: axisExpandWidth,\n            axisCollapseWidth: axisCollapseWidth,\n            axisExpandWindow: axisExpandWindow,\n            axisCount: axisCount,\n            winInnerIndices: winInnerIndices,\n            axisExpandWindow0Pos: axisExpandWindow0Pos\n        };\n    },\n\n    /**\n     * @private\n     */\n    _layoutAxes: function () {\n        var rect = this._rect;\n        var axes = this._axesMap;\n        var dimensions = this.dimensions;\n        var layoutInfo = this._makeLayoutInfo();\n        var layout = layoutInfo.layout;\n\n        axes.each(function (axis) {\n            var axisExtent = [0, layoutInfo.axisLength];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(axisExtent[idx], axisExtent[1 - idx]);\n        });\n\n        each$11(dimensions, function (dim, idx) {\n            var posInfo = (layoutInfo.axisExpandable\n                ? layoutAxisWithExpand : layoutAxisWithoutExpand\n            )(idx, layoutInfo);\n\n            var positionTable = {\n                horizontal: {\n                    x: posInfo.position,\n                    y: layoutInfo.axisLength\n                },\n                vertical: {\n                    x: 0,\n                    y: posInfo.position\n                }\n            };\n            var rotationTable = {\n                horizontal: PI$3 / 2,\n                vertical: 0\n            };\n\n            var position = [\n                positionTable[layout].x + rect.x,\n                positionTable[layout].y + rect.y\n            ];\n\n            var rotation = rotationTable[layout];\n            var transform = create$1();\n            rotate(transform, transform, rotation);\n            translate(transform, transform, position);\n\n            // TODO\n            // tick等排布信息。\n\n            // TODO\n            // 根据axis order 更新 dimensions顺序。\n\n            this._axesLayout[dim] = {\n                position: position,\n                rotation: rotation,\n                transform: transform,\n                axisNameAvailableWidth: posInfo.axisNameAvailableWidth,\n                axisLabelShow: posInfo.axisLabelShow,\n                nameTruncateMaxWidth: posInfo.nameTruncateMaxWidth,\n                tickDirection: 1,\n                labelDirection: 1\n            };\n        }, this);\n    },\n\n    /**\n     * Get axis by dim.\n     * @param {string} dim\n     * @return {module:echarts/coord/parallel/ParallelAxis} [description]\n     */\n    getAxis: function (dim) {\n        return this._axesMap.get(dim);\n    },\n\n    /**\n     * Convert a dim value of a single item of series data to Point.\n     * @param {*} value\n     * @param {string} dim\n     * @return {Array}\n     */\n    dataToPoint: function (value, dim) {\n        return this.axisCoordToPoint(\n            this._axesMap.get(dim).dataToCoord(value),\n            dim\n        );\n    },\n\n    /**\n     * Travel data for one time, get activeState of each data item.\n     * @param {module:echarts/data/List} data\n     * @param {Functio} cb param: {string} activeState 'active' or 'inactive' or 'normal'\n     *                            {number} dataIndex\n     * @param {number} [start=0] the start dataIndex that travel from.\n     * @param {number} [end=data.count()] the next dataIndex of the last dataIndex will be travel.\n     */\n    eachActiveState: function (data, callback, start, end) {\n        start == null && (start = 0);\n        end == null && (end = data.count());\n\n        var axesMap = this._axesMap;\n        var dimensions = this.dimensions;\n        var dataDimensions = [];\n        var axisModels = [];\n\n        each$1(dimensions, function (axisDim) {\n            dataDimensions.push(data.mapDimension(axisDim));\n            axisModels.push(axesMap.get(axisDim).model);\n        });\n\n        var hasActiveSet = this.hasAxisBrushed();\n\n        for (var dataIndex = start; dataIndex < end; dataIndex++) {\n            var activeState;\n\n            if (!hasActiveSet) {\n                activeState = 'normal';\n            }\n            else {\n                activeState = 'active';\n                var values = data.getValues(dataDimensions, dataIndex);\n                for (var j = 0, lenj = dimensions.length; j < lenj; j++) {\n                    var state = axisModels[j].getActiveState(values[j]);\n\n                    if (state === 'inactive') {\n                        activeState = 'inactive';\n                        break;\n                    }\n                }\n            }\n\n            callback(activeState, dataIndex);\n        }\n    },\n\n    /**\n     * Whether has any activeSet.\n     * @return {boolean}\n     */\n    hasAxisBrushed: function () {\n        var dimensions = this.dimensions;\n        var axesMap = this._axesMap;\n        var hasActiveSet = false;\n\n        for (var j = 0, lenj = dimensions.length; j < lenj; j++) {\n            if (axesMap.get(dimensions[j]).model.getActiveState() !== 'normal') {\n                hasActiveSet = true;\n            }\n        }\n\n        return hasActiveSet;\n    },\n\n    /**\n     * Convert coords of each axis to Point.\n     *  Return point. For example: [10, 20]\n     * @param {Array.<number>} coords\n     * @param {string} dim\n     * @return {Array.<number>}\n     */\n    axisCoordToPoint: function (coord, dim) {\n        var axisLayout = this._axesLayout[dim];\n        return applyTransform$1([coord, 0], axisLayout.transform);\n    },\n\n    /**\n     * Get axis layout.\n     */\n    getAxisLayout: function (dim) {\n        return clone(this._axesLayout[dim]);\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @return {Object} {axisExpandWindow, delta, behavior: 'jump' | 'slide' | 'none'}.\n     */\n    getSlidedAxisExpandWindow: function (point) {\n        var layoutInfo = this._makeLayoutInfo();\n        var pixelDimIndex = layoutInfo.pixelDimIndex;\n        var axisExpandWindow = layoutInfo.axisExpandWindow.slice();\n        var winSize = axisExpandWindow[1] - axisExpandWindow[0];\n        var extent = [0, layoutInfo.axisExpandWidth * (layoutInfo.axisCount - 1)];\n\n        // Out of the area of coordinate system.\n        if (!this.containPoint(point)) {\n            return {behavior: 'none', axisExpandWindow: axisExpandWindow};\n        }\n\n        // Conver the point from global to expand coordinates.\n        var pointCoord = point[pixelDimIndex] - layoutInfo.layoutBase - layoutInfo.axisExpandWindow0Pos;\n\n        // For dragging operation convenience, the window should not be\n        // slided when mouse is the center area of the window.\n        var delta;\n        var behavior = 'slide';\n        var axisCollapseWidth = layoutInfo.axisCollapseWidth;\n        var triggerArea = this._model.get('axisExpandSlideTriggerArea');\n        // But consider touch device, jump is necessary.\n        var useJump = triggerArea[0] != null;\n\n        if (axisCollapseWidth) {\n            if (useJump && axisCollapseWidth && pointCoord < winSize * triggerArea[0]) {\n                behavior = 'jump';\n                delta = pointCoord - winSize * triggerArea[2];\n            }\n            else if (useJump && axisCollapseWidth && pointCoord > winSize * (1 - triggerArea[0])) {\n                behavior = 'jump';\n                delta = pointCoord - winSize * (1 - triggerArea[2]);\n            }\n            else {\n                (delta = pointCoord - winSize * triggerArea[1]) >= 0\n                    && (delta = pointCoord - winSize * (1 - triggerArea[1])) <= 0\n                    && (delta = 0);\n            }\n            delta *= layoutInfo.axisExpandWidth / axisCollapseWidth;\n            delta\n                ? sliderMove(delta, axisExpandWindow, extent, 'all')\n                // Avoid nonsense triger on mousemove.\n                : (behavior = 'none');\n        }\n        // When screen is too narrow, make it visible and slidable, although it is hard to interact.\n        else {\n            var winSize = axisExpandWindow[1] - axisExpandWindow[0];\n            var pos = extent[1] * pointCoord / winSize;\n            axisExpandWindow = [mathMax$5(0, pos - winSize / 2)];\n            axisExpandWindow[1] = mathMin$5(extent[1], axisExpandWindow[0] + winSize);\n            axisExpandWindow[0] = axisExpandWindow[1] - winSize;\n        }\n\n        return {\n            axisExpandWindow: axisExpandWindow,\n            behavior: behavior\n        };\n    }\n};\n\nfunction restrict(len, extent) {\n    return mathMin$5(mathMax$5(len, extent[0]), extent[1]);\n}\n\nfunction layoutAxisWithoutExpand(axisIndex, layoutInfo) {\n    var step = layoutInfo.layoutLength / (layoutInfo.axisCount - 1);\n    return {\n        position: step * axisIndex,\n        axisNameAvailableWidth: step,\n        axisLabelShow: true\n    };\n}\n\nfunction layoutAxisWithExpand(axisIndex, layoutInfo) {\n    var layoutLength = layoutInfo.layoutLength;\n    var axisExpandWidth = layoutInfo.axisExpandWidth;\n    var axisCount = layoutInfo.axisCount;\n    var axisCollapseWidth = layoutInfo.axisCollapseWidth;\n    var winInnerIndices = layoutInfo.winInnerIndices;\n\n    var position;\n    var axisNameAvailableWidth = axisCollapseWidth;\n    var axisLabelShow = false;\n    var nameTruncateMaxWidth;\n\n    if (axisIndex < winInnerIndices[0]) {\n        position = axisIndex * axisCollapseWidth;\n        nameTruncateMaxWidth = axisCollapseWidth;\n    }\n    else if (axisIndex <= winInnerIndices[1]) {\n        position = layoutInfo.axisExpandWindow0Pos\n            + axisIndex * axisExpandWidth - layoutInfo.axisExpandWindow[0];\n        axisNameAvailableWidth = axisExpandWidth;\n        axisLabelShow = true;\n    }\n    else {\n        position = layoutLength - (axisCount - 1 - axisIndex) * axisCollapseWidth;\n        nameTruncateMaxWidth = axisCollapseWidth;\n    }\n\n    return {\n        position: position,\n        axisNameAvailableWidth: axisNameAvailableWidth,\n        axisLabelShow: axisLabelShow,\n        nameTruncateMaxWidth: nameTruncateMaxWidth\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parallel coordinate system creater.\n */\n\nfunction create$2(ecModel, api) {\n    var coordSysList = [];\n\n    ecModel.eachComponent('parallel', function (parallelModel, idx) {\n        var coordSys = new Parallel(parallelModel, ecModel, api);\n\n        coordSys.name = 'parallel_' + idx;\n        coordSys.resize(parallelModel, api);\n\n        parallelModel.coordinateSystem = coordSys;\n        coordSys.model = parallelModel;\n\n        coordSysList.push(coordSys);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'parallel') {\n            var parallelModel = ecModel.queryComponents({\n                mainType: 'parallel',\n                index: seriesModel.get('parallelIndex'),\n                id: seriesModel.get('parallelId')\n            })[0];\n            seriesModel.coordinateSystem = parallelModel.coordinateSystem;\n        }\n    });\n\n    return coordSysList;\n}\n\nCoordinateSystemManager.register('parallel', {create: create$2});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel$2 = ComponentModel.extend({\n\n    type: 'baseParallelAxis',\n\n    /**\n     * @type {module:echarts/coord/parallel/Axis}\n     */\n    axis: null,\n\n    /**\n     * @type {Array.<Array.<number>}\n     * @readOnly\n     */\n    activeIntervals: [],\n\n    /**\n     * @return {Object}\n     */\n    getAreaSelectStyle: function () {\n        return makeStyleMapper(\n            [\n                ['fill', 'color'],\n                ['lineWidth', 'borderWidth'],\n                ['stroke', 'borderColor'],\n                ['width', 'width'],\n                ['opacity', 'opacity']\n            ]\n        )(this.getModel('areaSelectStyle'));\n    },\n\n    /**\n     * The code of this feature is put on AxisModel but not ParallelAxis,\n     * because axisModel can be alive after echarts updating but instance of\n     * ParallelAxis having been disposed. this._activeInterval should be kept\n     * when action dispatched (i.e. legend click).\n     *\n     * @param {Array.<Array<number>>} intervals interval.length === 0\n     *                                          means set all active.\n     * @public\n     */\n    setActiveIntervals: function (intervals) {\n        var activeIntervals = this.activeIntervals = clone(intervals);\n\n        // Normalize\n        if (activeIntervals) {\n            for (var i = activeIntervals.length - 1; i >= 0; i--) {\n                asc(activeIntervals[i]);\n            }\n        }\n    },\n\n    /**\n     * @param {number|string} [value] When attempting to detect 'no activeIntervals set',\n     *                         value can not be input.\n     * @return {string} 'normal': no activeIntervals set,\n     *                  'active',\n     *                  'inactive'.\n     * @public\n     */\n    getActiveState: function (value) {\n        var activeIntervals = this.activeIntervals;\n\n        if (!activeIntervals.length) {\n            return 'normal';\n        }\n\n        if (value == null || isNaN(value)) {\n            return 'inactive';\n        }\n\n        // Simple optimization\n        if (activeIntervals.length === 1) {\n            var interval = activeIntervals[0];\n            if (interval[0] <= value && value <= interval[1]) {\n                return 'active';\n            }\n        }\n        else {\n            for (var i = 0, len = activeIntervals.length; i < len; i++) {\n                if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) {\n                    return 'active';\n                }\n            }\n        }\n\n        return 'inactive';\n    }\n\n});\n\nvar defaultOption$1 = {\n\n    type: 'value',\n\n    /**\n     * @type {Array.<number>}\n     */\n    dim: null, // 0, 1, 2, ...\n\n    // parallelIndex: null,\n\n    areaSelectStyle: {\n        width: 20,\n        borderWidth: 1,\n        borderColor: 'rgba(160,197,232)',\n        color: 'rgba(160,197,232)',\n        opacity: 0.3\n    },\n\n    realtime: true, // Whether realtime update view when select.\n\n    z: 10\n};\n\nmerge(AxisModel$2.prototype, axisModelCommonMixin);\n\nfunction getAxisType$1(axisName, option) {\n    return option.type || (option.data ? 'category' : 'value');\n}\n\naxisModelCreator('parallel', AxisModel$2, getAxisType$1, defaultOption$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.extend({\n\n    type: 'parallel',\n\n    dependencies: ['parallelAxis'],\n\n    /**\n     * @type {module:echarts/coord/parallel/Parallel}\n     */\n    coordinateSystem: null,\n\n    /**\n     * Each item like: 'dim0', 'dim1', 'dim2', ...\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * Coresponding to dimensions.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    parallelAxisIndex: null,\n\n    layoutMode: 'box',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 0,\n        left: 80,\n        top: 60,\n        right: 80,\n        bottom: 60,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n\n        layout: 'horizontal',      // 'horizontal' or 'vertical'\n\n        // FIXME\n        // naming?\n        axisExpandable: false,\n        axisExpandCenter: null,\n        axisExpandCount: 0,\n        axisExpandWidth: 50,      // FIXME '10%' ?\n        axisExpandRate: 17,\n        axisExpandDebounce: 50,\n        // [out, in, jumpTarget]. In percentage. If use [null, 0.05], null means full.\n        // Do not doc to user until necessary.\n        axisExpandSlideTriggerArea: [-0.15, 0.05, 0.4],\n        axisExpandTriggerOn: 'click', // 'mousemove' or 'click'\n\n        parallelAxisDefault: null\n    },\n\n    /**\n     * @override\n     */\n    init: function () {\n        ComponentModel.prototype.init.apply(this, arguments);\n\n        this.mergeOption({});\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var thisOption = this.option;\n\n        newOption && merge(thisOption, newOption, true);\n\n        this._initDimensions();\n    },\n\n    /**\n     * Whether series or axis is in this coordinate system.\n     * @param {module:echarts/model/Series|module:echarts/coord/parallel/AxisModel} model\n     * @param {module:echarts/model/Global} ecModel\n     */\n    contains: function (model, ecModel) {\n        var parallelIndex = model.get('parallelIndex');\n        return parallelIndex != null\n            && ecModel.getComponent('parallel', parallelIndex) === this;\n    },\n\n    setAxisExpand: function (opt) {\n        each$1(\n            ['axisExpandable', 'axisExpandCenter', 'axisExpandCount', 'axisExpandWidth', 'axisExpandWindow'],\n            function (name) {\n                if (opt.hasOwnProperty(name)) {\n                    this.option[name] = opt[name];\n                }\n            },\n            this\n        );\n    },\n\n    /**\n     * @private\n     */\n    _initDimensions: function () {\n        var dimensions = this.dimensions = [];\n        var parallelAxisIndex = this.parallelAxisIndex = [];\n\n        var axisModels = filter(this.dependentModels.parallelAxis, function (axisModel) {\n            // Can not use this.contains here, because\n            // initialization has not been completed yet.\n            return (axisModel.get('parallelIndex') || 0) === this.componentIndex;\n        }, this);\n\n        each$1(axisModels, function (axisModel) {\n            dimensions.push('dim' + axisModel.get('dim'));\n            parallelAxisIndex.push(axisModel.componentIndex);\n        });\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {string} parallelAxisId\n * @property {Array.<Array.<number>>} intervals\n */\nvar actionInfo$1 = {\n    type: 'axisAreaSelect',\n    event: 'axisAreaSelected'\n    // update: 'updateVisual'\n};\n\nregisterAction(actionInfo$1, function (payload, ecModel) {\n    ecModel.eachComponent(\n        {mainType: 'parallelAxis', query: payload},\n        function (parallelAxisModel) {\n            parallelAxisModel.axis.model.setActiveIntervals(payload.intervals);\n        }\n    );\n});\n\n/**\n * @payload\n */\nregisterAction('parallelAxisExpand', function (payload, ecModel) {\n    ecModel.eachComponent(\n        {mainType: 'parallel', query: payload},\n        function (parallelModel) {\n            parallelModel.setAxisExpand(payload);\n        }\n    );\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$2 = curry;\nvar each$12 = each$1;\nvar map$2 = map;\nvar mathMin$6 = Math.min;\nvar mathMax$6 = Math.max;\nvar mathPow$2 = Math.pow;\n\nvar COVER_Z = 10000;\nvar UNSELECT_THRESHOLD = 6;\nvar MIN_RESIZE_LINE_WIDTH = 6;\nvar MUTEX_RESOURCE_KEY = 'globalPan';\n\nvar DIRECTION_MAP = {\n    w: [0, 0],\n    e: [0, 1],\n    n: [1, 0],\n    s: [1, 1]\n};\nvar CURSOR_MAP = {\n    w: 'ew',\n    e: 'ew',\n    n: 'ns',\n    s: 'ns',\n    ne: 'nesw',\n    sw: 'nesw',\n    nw: 'nwse',\n    se: 'nwse'\n};\nvar DEFAULT_BRUSH_OPT = {\n    brushStyle: {\n        lineWidth: 2,\n        stroke: 'rgba(0,0,0,0.3)',\n        fill: 'rgba(0,0,0,0.1)'\n    },\n    transformable: true,\n    brushMode: 'single',\n    removeOnClick: false\n};\n\nvar baseUID = 0;\n\n/**\n * @alias module:echarts/component/helper/BrushController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n * @event module:echarts/component/helper/BrushController#brush\n *        params:\n *            areas: Array.<Array>, coord relates to container group,\n *                                    If no container specified, to global.\n *            opt {\n *                isEnd: boolean,\n *                removeOnClick: boolean\n *            }\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction BrushController(zr) {\n\n    if (__DEV__) {\n        assert$1(zr);\n    }\n\n    Eventful.call(this);\n\n    /**\n     * @type {module:zrender/zrender~ZRender}\n     * @private\n     */\n    this._zr = zr;\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *     'line', 'rect', 'polygon' or false\n     *     If passing false/null/undefined, disable brush.\n     *     If passing 'auto', determined by panel.defaultBrushType\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *\n     * @private\n     * @type {Object}\n     */\n    this._brushOption;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._panels;\n\n    /**\n     * @private\n     * @type {Array.<nubmer>}\n     */\n    this._track = [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._dragging;\n\n    /**\n     * @private\n     * @type {Array}\n     */\n    this._covers = [];\n\n    /**\n     * @private\n     * @type {moudule:zrender/container/Group}\n     */\n    this._creatingCover;\n\n    /**\n     * `true` means global panel\n     * @private\n     * @type {module:zrender/container/Group|boolean}\n     */\n    this._creatingPanel;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._enableGlobalPan;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    if (__DEV__) {\n        this._mounted;\n    }\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._uid = 'brushController_' + baseUID++;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._handlers = {};\n    each$12(mouseHandlers, function (handler, eventName) {\n        this._handlers[eventName] = bind(handler, this);\n    }, this);\n}\n\nBrushController.prototype = {\n\n    constructor: BrushController,\n\n    /**\n     * If set to null/undefined/false, select disabled.\n     * @param {Object} brushOption\n     * @param {string|boolean} brushOption.brushType 'line', 'rect', 'polygon' or false\n     *                          If passing false/null/undefined, disable brush.\n     *                          If passing 'auto', determined by panel.defaultBrushType.\n     *                              ('auto' can not be used in global panel)\n     * @param {number} [brushOption.brushMode='single'] 'single' or 'multiple'\n     * @param {boolean} [brushOption.transformable=true]\n     * @param {boolean} [brushOption.removeOnClick=false]\n     * @param {Object} [brushOption.brushStyle]\n     * @param {number} [brushOption.brushStyle.width]\n     * @param {number} [brushOption.brushStyle.lineWidth]\n     * @param {string} [brushOption.brushStyle.stroke]\n     * @param {string} [brushOption.brushStyle.fill]\n     * @param {number} [brushOption.z]\n     */\n    enableBrush: function (brushOption) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        this._brushType && doDisableBrush(this);\n        brushOption.brushType && doEnableBrush(this, brushOption);\n\n        return this;\n    },\n\n    /**\n     * @param {Array.<Object>} panelOpts If not pass, it is global brush.\n     *        Each items: {\n     *            panelId, // mandatory.\n     *            clipPath, // mandatory. function.\n     *            isTargetByCursor, // mandatory. function.\n     *            defaultBrushType, // optional, only used when brushType is 'auto'.\n     *            getLinearBrushOtherExtent, // optional. function.\n     *        }\n     */\n    setPanels: function (panelOpts) {\n        if (panelOpts && panelOpts.length) {\n            var panels = this._panels = {};\n            each$1(panelOpts, function (panelOpts) {\n                panels[panelOpts.panelId] = clone(panelOpts);\n            });\n        }\n        else {\n            this._panels = null;\n        }\n        return this;\n    },\n\n    /**\n     * @param {Object} [opt]\n     * @return {boolean} [opt.enableGlobalPan=false]\n     */\n    mount: function (opt) {\n        opt = opt || {};\n\n        if (__DEV__) {\n            this._mounted = true; // should be at first.\n        }\n\n        this._enableGlobalPan = opt.enableGlobalPan;\n\n        var thisGroup = this.group;\n        this._zr.add(thisGroup);\n\n        thisGroup.attr({\n            position: opt.position || [0, 0],\n            rotation: opt.rotation || 0,\n            scale: opt.scale || [1, 1]\n        });\n        this._transform = thisGroup.getLocalTransform();\n\n        return this;\n    },\n\n    eachCover: function (cb, context) {\n        each$12(this._covers, cb, context);\n    },\n\n    /**\n     * Update covers.\n     * @param {Array.<Object>} brushOptionList Like:\n     *        [\n     *            {id: 'xx', brushType: 'line', range: [23, 44], brushStyle, transformable},\n     *            {id: 'yy', brushType: 'rect', range: [[23, 44], [23, 54]]},\n     *            ...\n     *        ]\n     *        `brushType` is required in each cover info. (can not be 'auto')\n     *        `id` is not mandatory.\n     *        `brushStyle`, `transformable` is not mandatory, use DEFAULT_BRUSH_OPT by default.\n     *        If brushOptionList is null/undefined, all covers removed.\n     */\n    updateCovers: function (brushOptionList) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        brushOptionList = map(brushOptionList, function (brushOption) {\n            return merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n        });\n\n        var tmpIdPrefix = '\\0-brush-index-';\n        var oldCovers = this._covers;\n        var newCovers = this._covers = [];\n        var controller = this;\n        var creatingCover = this._creatingCover;\n\n        (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey))\n            .add(addOrUpdate)\n            .update(addOrUpdate)\n            .remove(remove)\n            .execute();\n\n        return this;\n\n        function getKey(brushOption, index) {\n            return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index)\n                + '-' + brushOption.brushType;\n        }\n\n        function oldGetKey(cover, index) {\n            return getKey(cover.__brushOption, index);\n        }\n\n        function addOrUpdate(newIndex, oldIndex) {\n            var newBrushOption = brushOptionList[newIndex];\n            // Consider setOption in event listener of brushSelect,\n            // where updating cover when creating should be forbiden.\n            if (oldIndex != null && oldCovers[oldIndex] === creatingCover) {\n                newCovers[newIndex] = oldCovers[oldIndex];\n            }\n            else {\n                var cover = newCovers[newIndex] = oldIndex != null\n                    ? (\n                        oldCovers[oldIndex].__brushOption = newBrushOption,\n                        oldCovers[oldIndex]\n                    )\n                    : endCreating(controller, createCover(controller, newBrushOption));\n                updateCoverAfterCreation(controller, cover);\n            }\n        }\n\n        function remove(oldIndex) {\n            if (oldCovers[oldIndex] !== creatingCover) {\n                controller.group.remove(oldCovers[oldIndex]);\n            }\n        }\n    },\n\n    unmount: function () {\n        if (__DEV__) {\n            if (!this._mounted) {\n                return;\n            }\n        }\n\n        this.enableBrush(false);\n\n        // container may 'removeAll' outside.\n        clearCovers(this);\n        this._zr.remove(this.group);\n\n        if (__DEV__) {\n            this._mounted = false; // should be at last.\n        }\n\n        return this;\n    },\n\n    dispose: function () {\n        this.unmount();\n        this.off();\n    }\n};\n\nmixin(BrushController, Eventful);\n\nfunction doEnableBrush(controller, brushOption) {\n    var zr = controller._zr;\n\n    // Consider roam, which takes globalPan too.\n    if (!controller._enableGlobalPan) {\n        take(zr, MUTEX_RESOURCE_KEY, controller._uid);\n    }\n\n    each$12(controller._handlers, function (handler, eventName) {\n        zr.on(eventName, handler);\n    });\n\n    controller._brushType = brushOption.brushType;\n    controller._brushOption = merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n}\n\nfunction doDisableBrush(controller) {\n    var zr = controller._zr;\n\n    release(zr, MUTEX_RESOURCE_KEY, controller._uid);\n\n    each$12(controller._handlers, function (handler, eventName) {\n        zr.off(eventName, handler);\n    });\n\n    controller._brushType = controller._brushOption = null;\n}\n\nfunction createCover(controller, brushOption) {\n    var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption);\n    cover.__brushOption = brushOption;\n    updateZ$1(cover, brushOption);\n    controller.group.add(cover);\n    return cover;\n}\n\nfunction endCreating(controller, creatingCover) {\n    var coverRenderer = getCoverRenderer(creatingCover);\n    if (coverRenderer.endCreating) {\n        coverRenderer.endCreating(controller, creatingCover);\n        updateZ$1(creatingCover, creatingCover.__brushOption);\n    }\n    return creatingCover;\n}\n\nfunction updateCoverShape(controller, cover) {\n    var brushOption = cover.__brushOption;\n    getCoverRenderer(cover).updateCoverShape(\n        controller, cover, brushOption.range, brushOption\n    );\n}\n\nfunction updateZ$1(cover, brushOption) {\n    var z = brushOption.z;\n    z == null && (z = COVER_Z);\n    cover.traverse(function (el) {\n        el.z = z;\n        el.z2 = z; // Consider in given container.\n    });\n}\n\nfunction updateCoverAfterCreation(controller, cover) {\n    getCoverRenderer(cover).updateCommon(controller, cover);\n    updateCoverShape(controller, cover);\n}\n\nfunction getCoverRenderer(cover) {\n    return coverRenderers[cover.__brushOption.brushType];\n}\n\n// return target panel or `true` (means global panel)\nfunction getPanelByPoint(controller, e, localCursorPoint) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panel;\n    var transform = controller._transform;\n    each$12(panels, function (pn) {\n        pn.isTargetByCursor(e, localCursorPoint, transform) && (panel = pn);\n    });\n    return panel;\n}\n\n// Return a panel or true\nfunction getPanelByCover(controller, cover) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panelId = cover.__brushOption.panelId;\n    // User may give cover without coord sys info,\n    // which is then treated as global panel.\n    return panelId != null ? panels[panelId] : true;\n}\n\nfunction clearCovers(controller) {\n    var covers = controller._covers;\n    var originalLength = covers.length;\n    each$12(covers, function (cover) {\n        controller.group.remove(cover);\n    }, controller);\n    covers.length = 0;\n\n    return !!originalLength;\n}\n\nfunction trigger$1(controller, opt) {\n    var areas = map$2(controller._covers, function (cover) {\n        var brushOption = cover.__brushOption;\n        var range = clone(brushOption.range);\n        return {\n            brushType: brushOption.brushType,\n            panelId: brushOption.panelId,\n            range: range\n        };\n    });\n\n    controller.trigger('brush', areas, {\n        isEnd: !!opt.isEnd,\n        removeOnClick: !!opt.removeOnClick\n    });\n}\n\nfunction shouldShowCover(controller) {\n    var track = controller._track;\n\n    if (!track.length) {\n        return false;\n    }\n\n    var p2 = track[track.length - 1];\n    var p1 = track[0];\n    var dx = p2[0] - p1[0];\n    var dy = p2[1] - p1[1];\n    var dist = mathPow$2(dx * dx + dy * dy, 0.5);\n\n    return dist > UNSELECT_THRESHOLD;\n}\n\nfunction getTrackEnds(track) {\n    var tail = track.length - 1;\n    tail < 0 && (tail = 0);\n    return [track[0], track[tail]];\n}\n\nfunction createBaseRectCover(doDrift, controller, brushOption, edgeNames) {\n    var cover = new Group();\n\n    cover.add(new Rect({\n        name: 'main',\n        style: makeStyle(brushOption),\n        silent: true,\n        draggable: true,\n        cursor: 'move',\n        drift: curry$2(doDrift, controller, cover, 'nswe'),\n        ondragend: curry$2(trigger$1, controller, {isEnd: true})\n    }));\n\n    each$12(\n        edgeNames,\n        function (name) {\n            cover.add(new Rect({\n                name: name,\n                style: {opacity: 0},\n                draggable: true,\n                silent: true,\n                invisible: true,\n                drift: curry$2(doDrift, controller, cover, name),\n                ondragend: curry$2(trigger$1, controller, {isEnd: true})\n            }));\n        }\n    );\n\n    return cover;\n}\n\nfunction updateBaseRect(controller, cover, localRange, brushOption) {\n    var lineWidth = brushOption.brushStyle.lineWidth || 0;\n    var handleSize = mathMax$6(lineWidth, MIN_RESIZE_LINE_WIDTH);\n    var x = localRange[0][0];\n    var y = localRange[1][0];\n    var xa = x - lineWidth / 2;\n    var ya = y - lineWidth / 2;\n    var x2 = localRange[0][1];\n    var y2 = localRange[1][1];\n    var x2a = x2 - handleSize + lineWidth / 2;\n    var y2a = y2 - handleSize + lineWidth / 2;\n    var width = x2 - x;\n    var height = y2 - y;\n    var widtha = width + lineWidth;\n    var heighta = height + lineWidth;\n\n    updateRectShape(controller, cover, 'main', x, y, width, height);\n\n    if (brushOption.transformable) {\n        updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize);\n        updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize);\n\n        updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize);\n        updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize);\n    }\n}\n\nfunction updateCommon(controller, cover) {\n    var brushOption = cover.__brushOption;\n    var transformable = brushOption.transformable;\n\n    var mainEl = cover.childAt(0);\n    mainEl.useStyle(makeStyle(brushOption));\n    mainEl.attr({\n        silent: !transformable,\n        cursor: transformable ? 'move' : 'default'\n    });\n\n    each$12(\n        ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'],\n        function (name) {\n            var el = cover.childOfName(name);\n            var globalDir = getGlobalDirection(controller, name);\n\n            el && el.attr({\n                silent: !transformable,\n                invisible: !transformable,\n                cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null\n            });\n        }\n    );\n}\n\nfunction updateRectShape(controller, cover, name, x, y, w, h) {\n    var el = cover.childOfName(name);\n    el && el.setShape(pointsToRect(\n        clipByPanel(controller, cover, [[x, y], [x + w, y + h]])\n    ));\n}\n\nfunction makeStyle(brushOption) {\n    return defaults({strokeNoScale: true}, brushOption.brushStyle);\n}\n\nfunction formatRectRange(x, y, x2, y2) {\n    var min = [mathMin$6(x, x2), mathMin$6(y, y2)];\n    var max = [mathMax$6(x, x2), mathMax$6(y, y2)];\n\n    return [\n        [min[0], max[0]], // x range\n        [min[1], max[1]] // y range\n    ];\n}\n\nfunction getTransform$1(controller) {\n    return getTransform(controller.group);\n}\n\nfunction getGlobalDirection(controller, localDirection) {\n    if (localDirection.length > 1) {\n        localDirection = localDirection.split('');\n        var globalDir = [\n            getGlobalDirection(controller, localDirection[0]),\n            getGlobalDirection(controller, localDirection[1])\n        ];\n        (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse();\n        return globalDir.join('');\n    }\n    else {\n        var map$$1 = {w: 'left', e: 'right', n: 'top', s: 'bottom'};\n        var inverseMap = {left: 'w', right: 'e', top: 'n', bottom: 's'};\n        var globalDir = transformDirection(\n            map$$1[localDirection], getTransform$1(controller)\n        );\n        return inverseMap[globalDir];\n    }\n}\n\nfunction driftRect(toRectRange, fromRectRange, controller, cover, name, dx, dy, e) {\n    var brushOption = cover.__brushOption;\n    var rectRange = toRectRange(brushOption.range);\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$12(name.split(''), function (namePart) {\n        var ind = DIRECTION_MAP[namePart];\n        rectRange[ind[0]][ind[1]] += localDelta[ind[0]];\n    });\n\n    brushOption.range = fromRectRange(formatRectRange(\n        rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1]\n    ));\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction driftPolygon(controller, cover, dx, dy, e) {\n    var range = cover.__brushOption.range;\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$12(range, function (point) {\n        point[0] += localDelta[0];\n        point[1] += localDelta[1];\n    });\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction toLocalDelta(controller, dx, dy) {\n    var thisGroup = controller.group;\n    var localD = thisGroup.transformCoordToLocal(dx, dy);\n    var localZero = thisGroup.transformCoordToLocal(0, 0);\n\n    return [localD[0] - localZero[0], localD[1] - localZero[1]];\n}\n\nfunction clipByPanel(controller, cover, data) {\n    var panel = getPanelByCover(controller, cover);\n\n    return (panel && panel !== true)\n        ? panel.clipPath(data, controller._transform)\n        : clone(data);\n}\n\nfunction pointsToRect(points) {\n    var xmin = mathMin$6(points[0][0], points[1][0]);\n    var ymin = mathMin$6(points[0][1], points[1][1]);\n    var xmax = mathMax$6(points[0][0], points[1][0]);\n    var ymax = mathMax$6(points[0][1], points[1][1]);\n\n    return {\n        x: xmin,\n        y: ymin,\n        width: xmax - xmin,\n        height: ymax - ymin\n    };\n}\n\nfunction resetCursor(controller, e, localCursorPoint) {\n    // Check active\n    if (!controller._brushType) {\n        return;\n    }\n\n    var zr = controller._zr;\n    var covers = controller._covers;\n    var currPanel = getPanelByPoint(controller, e, localCursorPoint);\n\n    // Check whether in covers.\n    if (!controller._dragging) {\n        for (var i = 0; i < covers.length; i++) {\n            var brushOption = covers[i].__brushOption;\n            if (currPanel\n                && (currPanel === true || brushOption.panelId === currPanel.panelId)\n                && coverRenderers[brushOption.brushType].contain(\n                    covers[i], localCursorPoint[0], localCursorPoint[1]\n                )\n            ) {\n                // Use cursor style set on cover.\n                return;\n            }\n        }\n    }\n\n    currPanel && zr.setCursorStyle('crosshair');\n}\n\nfunction preventDefault(e) {\n    var rawE = e.event;\n    rawE.preventDefault && rawE.preventDefault();\n}\n\nfunction mainShapeContain(cover, x, y) {\n    return cover.childOfName('main').contain(x, y);\n}\n\nfunction updateCoverByMouse(controller, e, localCursorPoint, isEnd) {\n    var creatingCover = controller._creatingCover;\n    var panel = controller._creatingPanel;\n    var thisBrushOption = controller._brushOption;\n    var eventParams;\n\n    controller._track.push(localCursorPoint.slice());\n\n    if (shouldShowCover(controller) || creatingCover) {\n\n        if (panel && !creatingCover) {\n            thisBrushOption.brushMode === 'single' && clearCovers(controller);\n            var brushOption = clone(thisBrushOption);\n            brushOption.brushType = determineBrushType(brushOption.brushType, panel);\n            brushOption.panelId = panel === true ? null : panel.panelId;\n            creatingCover = controller._creatingCover = createCover(controller, brushOption);\n            controller._covers.push(creatingCover);\n        }\n\n        if (creatingCover) {\n            var coverRenderer = coverRenderers[determineBrushType(controller._brushType, panel)];\n            var coverBrushOption = creatingCover.__brushOption;\n\n            coverBrushOption.range = coverRenderer.getCreatingRange(\n                clipByPanel(controller, creatingCover, controller._track)\n            );\n\n            if (isEnd) {\n                endCreating(controller, creatingCover);\n                coverRenderer.updateCommon(controller, creatingCover);\n            }\n\n            updateCoverShape(controller, creatingCover);\n\n            eventParams = {isEnd: isEnd};\n        }\n    }\n    else if (\n        isEnd\n        && thisBrushOption.brushMode === 'single'\n        && thisBrushOption.removeOnClick\n    ) {\n        // Help user to remove covers easily, only by a tiny drag, in 'single' mode.\n        // But a single click do not clear covers, because user may have casual\n        // clicks (for example, click on other component and do not expect covers\n        // disappear).\n        // Only some cover removed, trigger action, but not every click trigger action.\n        if (getPanelByPoint(controller, e, localCursorPoint) && clearCovers(controller)) {\n            eventParams = {isEnd: isEnd, removeOnClick: true};\n        }\n    }\n\n    return eventParams;\n}\n\nfunction determineBrushType(brushType, panel) {\n    if (brushType === 'auto') {\n        if (__DEV__) {\n            assert$1(\n                panel && panel.defaultBrushType,\n                'MUST have defaultBrushType when brushType is \"atuo\"'\n            );\n        }\n        return panel.defaultBrushType;\n    }\n    return brushType;\n}\n\nvar mouseHandlers = {\n\n    mousedown: function (e) {\n        if (this._dragging) {\n            // In case some browser do not support globalOut,\n            // and release mose out side the browser.\n            handleDragEnd.call(this, e);\n        }\n        else if (!e.target || !e.target.draggable) {\n\n            preventDefault(e);\n\n            var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n            this._creatingCover = null;\n            var panel = this._creatingPanel = getPanelByPoint(this, e, localCursorPoint);\n\n            if (panel) {\n                this._dragging = true;\n                this._track = [localCursorPoint.slice()];\n            }\n        }\n    },\n\n    mousemove: function (e) {\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        resetCursor(this, e, localCursorPoint);\n\n        if (this._dragging) {\n\n            preventDefault(e);\n\n            var eventParams = updateCoverByMouse(this, e, localCursorPoint, false);\n\n            eventParams && trigger$1(this, eventParams);\n        }\n    },\n\n    mouseup: handleDragEnd //,\n\n    // FIXME\n    // in tooltip, globalout should not be triggered.\n    // globalout: handleDragEnd\n};\n\nfunction handleDragEnd(e) {\n    if (this._dragging) {\n\n        preventDefault(e);\n\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n        var eventParams = updateCoverByMouse(this, e, localCursorPoint, true);\n\n        this._dragging = false;\n        this._track = [];\n        this._creatingCover = null;\n\n        // trigger event shoule be at final, after procedure will be nested.\n        eventParams && trigger$1(this, eventParams);\n    }\n}\n\n/**\n * key: brushType\n * @type {Object}\n */\nvar coverRenderers = {\n\n    lineX: getLineRenderer(0),\n\n    lineY: getLineRenderer(1),\n\n    rect: {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$2(\n                    driftRect,\n                    function (range) {\n                        return range;\n                    },\n                    function (range) {\n                        return range;\n                    }\n                ),\n                controller,\n                brushOption,\n                ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw']\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]);\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            updateBaseRect(controller, cover, localRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    },\n\n    polygon: {\n        createCover: function (controller, brushOption) {\n            var cover = new Group();\n\n            // Do not use graphic.Polygon because graphic.Polyline do not close the\n            // border of the shape when drawing, which is a better experience for user.\n            cover.add(new Polyline({\n                name: 'main',\n                style: makeStyle(brushOption),\n                silent: true\n            }));\n\n            return cover;\n        },\n        getCreatingRange: function (localTrack) {\n            return localTrack;\n        },\n        endCreating: function (controller, cover) {\n            cover.remove(cover.childAt(0));\n            // Use graphic.Polygon close the shape.\n            cover.add(new Polygon({\n                name: 'main',\n                draggable: true,\n                drift: curry$2(driftPolygon, controller, cover),\n                ondragend: curry$2(trigger$1, controller, {isEnd: true})\n            }));\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            cover.childAt(0).setShape({\n                points: clipByPanel(controller, cover, localRange)\n            });\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    }\n};\n\nfunction getLineRenderer(xyIndex) {\n    return {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$2(\n                    driftRect,\n                    function (range) {\n                        var rectRange = [range, [0, 100]];\n                        xyIndex && rectRange.reverse();\n                        return rectRange;\n                    },\n                    function (rectRange) {\n                        return rectRange[xyIndex];\n                    }\n                ),\n                controller,\n                brushOption,\n                [['w', 'e'], ['n', 's']][xyIndex]\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            var min = mathMin$6(ends[0][xyIndex], ends[1][xyIndex]);\n            var max = mathMax$6(ends[0][xyIndex], ends[1][xyIndex]);\n\n            return [min, max];\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            var otherExtent;\n            // If brushWidth not specified, fit the panel.\n            var panel = getPanelByCover(controller, cover);\n            if (panel !== true && panel.getLinearBrushOtherExtent) {\n                otherExtent = panel.getLinearBrushOtherExtent(\n                    xyIndex, controller._transform\n                );\n            }\n            else {\n                var zr = controller._zr;\n                otherExtent = [0, [zr.getWidth(), zr.getHeight()][1 - xyIndex]];\n            }\n            var rectRange = [localRange, otherExtent];\n            xyIndex && rectRange.reverse();\n\n            updateBaseRect(controller, cover, rectRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeRectPanelClipPath(rect) {\n    rect = normalizeRect(rect);\n    return function (localPoints, transform) {\n        return clipPointsByRect(localPoints, rect);\n    };\n}\n\nfunction makeLinearBrushOtherExtent(rect, specifiedXYIndex) {\n    rect = normalizeRect(rect);\n    return function (xyIndex) {\n        var idx = specifiedXYIndex != null ? specifiedXYIndex : xyIndex;\n        var brushWidth = idx ? rect.width : rect.height;\n        var base = idx ? rect.x : rect.y;\n        return [base, base + (brushWidth || 0)];\n    };\n}\n\nfunction makeRectIsTargetByCursor(rect, api, targetModel) {\n    rect = normalizeRect(rect);\n    return function (e, localCursorPoint, transform) {\n        return rect.contain(localCursorPoint[0], localCursorPoint[1])\n            && !onIrrelevantElement(e, api, targetModel);\n    };\n}\n\n// Consider width/height is negative.\nfunction normalizeRect(rect) {\n    return BoundingRect.create(rect);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar elementList = ['axisLine', 'axisTickLabel', 'axisName'];\n\nvar AxisView$2 = extendComponentView({\n\n    type: 'parallelAxis',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        AxisView$2.superApply(this, 'init', arguments);\n\n        /**\n         * @type {module:echarts/component/helper/BrushController}\n         */\n        (this._brushController = new BrushController(api.getZr()))\n            .on('brush', bind(this._onBrush, this));\n    },\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        if (fromAxisAreaSelect(axisModel, ecModel, payload)) {\n            return;\n        }\n\n        this.axisModel = axisModel;\n        this.api = api;\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var coordSysModel = getCoordSysModel(axisModel, ecModel);\n        var coordSys = coordSysModel.coordinateSystem;\n\n        var areaSelectStyle = axisModel.getAreaSelectStyle();\n        var areaWidth = areaSelectStyle.width;\n\n        var dim = axisModel.axis.dim;\n        var axisLayout = coordSys.getAxisLayout(dim);\n\n        var builderOpt = extend(\n            {strokeContainThreshold: areaWidth},\n            axisLayout\n        );\n\n        var axisBuilder = new AxisBuilder(axisModel, builderOpt);\n\n        each$1(elementList, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        this._refreshBrushController(\n            builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api\n        );\n\n        var animationModel = (payload && payload.animation === false) ? null : axisModel;\n        groupTransition(oldAxisGroup, this._axisGroup, animationModel);\n    },\n\n    // /**\n    //  * @override\n    //  */\n    // updateVisual: function (axisModel, ecModel, api, payload) {\n    //     this._brushController && this._brushController\n    //         .updateCovers(getCoverInfoList(axisModel));\n    // },\n\n    _refreshBrushController: function (\n        builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api\n    ) {\n        // After filtering, axis may change, select area needs to be update.\n        var extent = axisModel.axis.getExtent();\n        var extentLen = extent[1] - extent[0];\n        var extra = Math.min(30, Math.abs(extentLen) * 0.1); // Arbitrary value.\n\n        // width/height might be negative, which will be\n        // normalized in BoundingRect.\n        var rect = BoundingRect.create({\n            x: extent[0],\n            y: -areaWidth / 2,\n            width: extentLen,\n            height: areaWidth\n        });\n        rect.x -= extra;\n        rect.width += 2 * extra;\n\n        this._brushController\n            .mount({\n                enableGlobalPan: true,\n                rotation: builderOpt.rotation,\n                position: builderOpt.position\n            })\n            .setPanels([{\n                panelId: 'pl',\n                clipPath: makeRectPanelClipPath(rect),\n                isTargetByCursor: makeRectIsTargetByCursor(rect, api, coordSysModel),\n                getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect, 0)\n            }])\n            .enableBrush({\n                brushType: 'lineX',\n                brushStyle: areaSelectStyle,\n                removeOnClick: true\n            })\n            .updateCovers(getCoverInfoList(axisModel));\n    },\n\n    _onBrush: function (coverInfoList, opt) {\n        // Do not cache these object, because the mey be changed.\n        var axisModel = this.axisModel;\n        var axis = axisModel.axis;\n        var intervals = map(coverInfoList, function (coverInfo) {\n            return [\n                axis.coordToData(coverInfo.range[0], true),\n                axis.coordToData(coverInfo.range[1], true)\n            ];\n        });\n\n        // If realtime is true, action is not dispatched on drag end, because\n        // the drag end emits the same params with the last drag move event,\n        // and may have some delay when using touch pad.\n        if (!axisModel.option.realtime === opt.isEnd || opt.removeOnClick) { // jshint ignore:line\n            this.api.dispatchAction({\n                type: 'axisAreaSelect',\n                parallelAxisId: axisModel.id,\n                intervals: intervals\n            });\n        }\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._brushController.dispose();\n    }\n});\n\nfunction fromAxisAreaSelect(axisModel, ecModel, payload) {\n    return payload\n        && payload.type === 'axisAreaSelect'\n        && ecModel.findComponents(\n            {mainType: 'parallelAxis', query: payload}\n        )[0] === axisModel;\n}\n\nfunction getCoverInfoList(axisModel) {\n    var axis = axisModel.axis;\n    return map(axisModel.activeIntervals, function (interval) {\n        return {\n            brushType: 'lineX',\n            panelId: 'pl',\n            range: [\n                axis.dataToCoord(interval[0], true),\n                axis.dataToCoord(interval[1], true)\n            ]\n        };\n    });\n}\n\nfunction getCoordSysModel(axisModel, ecModel) {\n    return ecModel.getComponent(\n        'parallel', axisModel.get('parallelIndex')\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CLICK_THRESHOLD = 5; // > 4\n\n// Parallel view\nextendComponentView({\n    type: 'parallel',\n\n    render: function (parallelModel, ecModel, api) {\n        this._model = parallelModel;\n        this._api = api;\n\n        if (!this._handlers) {\n            this._handlers = {};\n            each$1(handlers, function (handler, eventName) {\n                api.getZr().on(eventName, this._handlers[eventName] = bind(handler, this));\n            }, this);\n        }\n\n        createOrUpdate(\n            this,\n            '_throttledDispatchExpand',\n            parallelModel.get('axisExpandRate'),\n            'fixRate'\n        );\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._handlers, function (handler, eventName) {\n            api.getZr().off(eventName, handler);\n        });\n        this._handlers = null;\n    },\n\n    /**\n     * @param {Object} [opt] If null, cancle the last action triggering for debounce.\n     */\n    _throttledDispatchExpand: function (opt) {\n        this._dispatchExpand(opt);\n    },\n\n    _dispatchExpand: function (opt) {\n        opt && this._api.dispatchAction(\n            extend({type: 'parallelAxisExpand'}, opt)\n        );\n    }\n\n});\n\nvar handlers = {\n\n    mousedown: function (e) {\n        if (checkTrigger(this, 'click')) {\n            this._mouseDownPoint = [e.offsetX, e.offsetY];\n        }\n    },\n\n    mouseup: function (e) {\n        var mouseDownPoint = this._mouseDownPoint;\n\n        if (checkTrigger(this, 'click') && mouseDownPoint) {\n            var point = [e.offsetX, e.offsetY];\n            var dist = Math.pow(mouseDownPoint[0] - point[0], 2)\n                + Math.pow(mouseDownPoint[1] - point[1], 2);\n\n            if (dist > CLICK_THRESHOLD) {\n                return;\n            }\n\n            var result = this._model.coordinateSystem.getSlidedAxisExpandWindow(\n                [e.offsetX, e.offsetY]\n            );\n\n            result.behavior !== 'none' && this._dispatchExpand({\n                axisExpandWindow: result.axisExpandWindow\n            });\n        }\n\n        this._mouseDownPoint = null;\n    },\n\n    mousemove: function (e) {\n        // Should do nothing when brushing.\n        if (this._mouseDownPoint || !checkTrigger(this, 'mousemove')) {\n            return;\n        }\n        var model = this._model;\n        var result = model.coordinateSystem.getSlidedAxisExpandWindow(\n            [e.offsetX, e.offsetY]\n        );\n\n        var behavior = result.behavior;\n        behavior === 'jump' && this._throttledDispatchExpand.debounceNextCall(model.get('axisExpandDebounce'));\n        this._throttledDispatchExpand(\n            behavior === 'none'\n                ? null // Cancle the last trigger, in case that mouse slide out of the area quickly.\n                : {\n                    axisExpandWindow: result.axisExpandWindow,\n                    // Jumping uses animation, and sliding suppresses animation.\n                    animation: behavior === 'jump' ? null : false\n                }\n        );\n    }\n};\n\nfunction checkTrigger(view, triggerOn) {\n    var model = view._model;\n    return model.get('axisExpandable') && model.get('axisExpandTriggerOn') === triggerOn;\n}\n\nregisterPreprocessor(parallelPreprocessor);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.parallel',\n\n    dependencies: ['parallel'],\n\n    visualColorAccessPath: 'lineStyle.color',\n\n    getInitialData: function (option, ecModel) {\n        var source = this.getSource();\n\n        setEncodeAndDimensions(source, this);\n\n        return createListFromArray(source, this);\n    },\n\n    /**\n     * User can get data raw indices on 'axisAreaSelected' event received.\n     *\n     * @public\n     * @param {string} activeState 'active' or 'inactive' or 'normal'\n     * @return {Array.<number>} Raw indices\n     */\n    getRawIndicesByActiveState: function (activeState) {\n        var coordSys = this.coordinateSystem;\n        var data = this.getData();\n        var indices = [];\n\n        coordSys.eachActiveState(data, function (theActiveState, dataIndex) {\n            if (activeState === theActiveState) {\n                indices.push(data.getRawIndex(dataIndex));\n            }\n        });\n\n        return indices;\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n\n        coordinateSystem: 'parallel',\n        parallelIndex: 0,\n\n        label: {\n            show: false\n        },\n\n        inactiveOpacity: 0.05,\n        activeOpacity: 1,\n\n        lineStyle: {\n            width: 1,\n            opacity: 0.45,\n            type: 'solid'\n        },\n        emphasis: {\n            label: {\n                show: false\n            }\n        },\n\n        progressive: 500,\n        smooth: false, // true | false | number\n\n        animationEasing: 'linear'\n    }\n});\n\nfunction setEncodeAndDimensions(source, seriesModel) {\n    // The mapping of parallelAxis dimension to data dimension can\n    // be specified in parallelAxis.option.dim. For example, if\n    // parallelAxis.option.dim is 'dim3', it mapping to the third\n    // dimension of data. But `data.encode` has higher priority.\n    // Moreover, parallelModel.dimension should not be regarded as data\n    // dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6'];\n\n    if (source.encodeDefine) {\n        return;\n    }\n\n    var parallelModel = seriesModel.ecModel.getComponent(\n        'parallel', seriesModel.get('parallelIndex')\n    );\n    if (!parallelModel) {\n        return;\n    }\n\n    var encodeDefine = source.encodeDefine = createHashMap();\n    each$1(parallelModel.dimensions, function (axisDim) {\n        var dataDimIndex = convertDimNameToNumber(axisDim);\n        encodeDefine.set(axisDim, dataDimIndex);\n    });\n}\n\nfunction convertDimNameToNumber(dimName) {\n    return +dimName.replace('dim', '');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_SMOOTH = 0.3;\n\nvar ParallelView = Chart.extend({\n\n    type: 'parallel',\n\n    init: function () {\n\n        /**\n         * @type {module:zrender/container/Group}\n         * @private\n         */\n        this._dataGroup = new Group();\n\n        this.group.add(this._dataGroup);\n\n        /**\n         * @type {module:echarts/data/List}\n         */\n        this._data;\n\n        /**\n         * @type {boolean}\n         */\n        this._initialized;\n    },\n\n    /**\n     * @override\n     */\n    render: function (seriesModel, ecModel, api, payload) {\n        var dataGroup = this._dataGroup;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var coordSys = seriesModel.coordinateSystem;\n        var dimensions = coordSys.dimensions;\n        var seriesScope = makeSeriesScope$2(seriesModel);\n\n        data.diff(oldData)\n            .add(add)\n            .update(update)\n            .remove(remove)\n            .execute();\n\n        function add(newDataIndex) {\n            var line = addEl(data, dataGroup, newDataIndex, dimensions, coordSys);\n            updateElCommon(line, data, newDataIndex, seriesScope);\n        }\n\n        function update(newDataIndex, oldDataIndex) {\n            var line = oldData.getItemGraphicEl(oldDataIndex);\n            var points = createLinePoints(data, newDataIndex, dimensions, coordSys);\n            data.setItemGraphicEl(newDataIndex, line);\n            var animationModel = (payload && payload.animation === false) ? null : seriesModel;\n            updateProps(line, {shape: {points: points}}, animationModel, newDataIndex);\n\n            updateElCommon(line, data, newDataIndex, seriesScope);\n        }\n\n        function remove(oldDataIndex) {\n            var line = oldData.getItemGraphicEl(oldDataIndex);\n            dataGroup.remove(line);\n        }\n\n        // First create\n        if (!this._initialized) {\n            this._initialized = true;\n            var clipPath = createGridClipShape$1(\n                coordSys, seriesModel, function () {\n                    // Callback will be invoked immediately if there is no animation\n                    setTimeout(function () {\n                        dataGroup.removeClipPath();\n                    });\n                }\n            );\n            dataGroup.setClipPath(clipPath);\n        }\n\n        this._data = data;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._initialized = true;\n        this._data = null;\n        this._dataGroup.removeAll();\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var coordSys = seriesModel.coordinateSystem;\n        var dimensions = coordSys.dimensions;\n        var seriesScope = makeSeriesScope$2(seriesModel);\n\n        for (var dataIndex = taskParams.start; dataIndex < taskParams.end; dataIndex++) {\n            var line = addEl(data, this._dataGroup, dataIndex, dimensions, coordSys);\n            line.incremental = true;\n            updateElCommon(line, data, dataIndex, seriesScope);\n        }\n    },\n\n    dispose: function () {},\n\n    // _renderForProgressive: function (seriesModel) {\n    //     var dataGroup = this._dataGroup;\n    //     var data = seriesModel.getData();\n    //     var oldData = this._data;\n    //     var coordSys = seriesModel.coordinateSystem;\n    //     var dimensions = coordSys.dimensions;\n    //     var option = seriesModel.option;\n    //     var progressive = option.progressive;\n    //     var smooth = option.smooth ? SMOOTH : null;\n\n    //     // In progressive animation is disabled, so use simple data diff,\n    //     // which effects performance less.\n    //     // (Typically performance for data with length 7000+ like:\n    //     // simpleDiff: 60ms, addEl: 184ms,\n    //     // in RMBP 2.4GHz intel i7, OSX 10.9 chrome 50.0.2661.102 (64-bit))\n    //     if (simpleDiff(oldData, data, dimensions)) {\n    //         dataGroup.removeAll();\n    //         data.each(function (dataIndex) {\n    //             addEl(data, dataGroup, dataIndex, dimensions, coordSys);\n    //         });\n    //     }\n\n    //     updateElCommon(data, progressive, smooth);\n\n    //     // Consider switch between progressive and not.\n    //     data.__plProgressive = true;\n    //     this._data = data;\n    // },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._dataGroup && this._dataGroup.removeAll();\n        this._data = null;\n    }\n});\n\nfunction createGridClipShape$1(coordSys, seriesModel, cb) {\n    var parallelModel = coordSys.model;\n    var rect = coordSys.getRect();\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        }\n    });\n\n    var dim = parallelModel.get('layout') === 'horizontal' ? 'width' : 'height';\n    rectEl.setShape(dim, 0);\n    initProps(rectEl, {\n        shape: {\n            width: rect.width,\n            height: rect.height\n        }\n    }, seriesModel, cb);\n    return rectEl;\n}\n\nfunction createLinePoints(data, dataIndex, dimensions, coordSys) {\n    var points = [];\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimName = dimensions[i];\n        var value = data.get(data.mapDimension(dimName), dataIndex);\n        if (!isEmptyValue(value, coordSys.getAxis(dimName).type)) {\n            points.push(coordSys.dataToPoint(value, dimName));\n        }\n    }\n    return points;\n}\n\nfunction addEl(data, dataGroup, dataIndex, dimensions, coordSys) {\n    var points = createLinePoints(data, dataIndex, dimensions, coordSys);\n    var line = new Polyline({\n        shape: {points: points},\n        silent: true,\n        z2: 10\n    });\n    dataGroup.add(line);\n    data.setItemGraphicEl(dataIndex, line);\n    return line;\n}\n\nfunction makeSeriesScope$2(seriesModel) {\n    var smooth = seriesModel.get('smooth', true);\n    smooth === true && (smooth = DEFAULT_SMOOTH);\n    return {\n        lineStyle: seriesModel.getModel('lineStyle').getLineStyle(),\n        smooth: smooth != null ? smooth : DEFAULT_SMOOTH\n    };\n}\n\nfunction updateElCommon(el, data, dataIndex, seriesScope) {\n    var lineStyle = seriesScope.lineStyle;\n\n    if (data.hasItemOption) {\n        var lineStyleModel = data.getItemModel(dataIndex).getModel('lineStyle');\n        lineStyle = lineStyleModel.getLineStyle();\n    }\n\n    el.useStyle(lineStyle);\n\n    var elStyle = el.style;\n    elStyle.fill = null;\n    // lineStyle.color have been set to itemVisual in module:echarts/visual/seriesColor.\n    elStyle.stroke = data.getItemVisual(dataIndex, 'color');\n    // lineStyle.opacity have been set to itemVisual in parallelVisual.\n    elStyle.opacity = data.getItemVisual(dataIndex, 'opacity');\n\n    seriesScope.smooth && (el.shape.smooth = seriesScope.smooth);\n}\n\n// function simpleDiff(oldData, newData, dimensions) {\n//     var oldLen;\n//     if (!oldData\n//         || !oldData.__plProgressive\n//         || (oldLen = oldData.count()) !== newData.count()\n//     ) {\n//         return true;\n//     }\n\n//     var dimLen = dimensions.length;\n//     for (var i = 0; i < oldLen; i++) {\n//         for (var j = 0; j < dimLen; j++) {\n//             if (oldData.get(dimensions[j], i) !== newData.get(dimensions[j], i)) {\n//                 return true;\n//             }\n//         }\n//     }\n\n//     return false;\n// }\n\n// FIXME\n// 公用方法?\nfunction isEmptyValue(val, axisType) {\n    return axisType === 'category'\n        ? val == null\n        : (val == null || isNaN(val)); // axisType === 'value'\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar opacityAccessPath$1 = ['lineStyle', 'normal', 'opacity'];\n\nvar parallelVisual = {\n\n    seriesType: 'parallel',\n\n    reset: function (seriesModel, ecModel, api) {\n\n        var itemStyleModel = seriesModel.getModel('itemStyle');\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var globalColors = ecModel.get('color');\n\n        var color = lineStyleModel.get('color')\n            || itemStyleModel.get('color')\n            || globalColors[seriesModel.seriesIndex % globalColors.length];\n        var inactiveOpacity = seriesModel.get('inactiveOpacity');\n        var activeOpacity = seriesModel.get('activeOpacity');\n        var lineStyle = seriesModel.getModel('lineStyle').getLineStyle();\n\n        var coordSys = seriesModel.coordinateSystem;\n        var data = seriesModel.getData();\n\n        var opacityMap = {\n            normal: lineStyle.opacity,\n            active: activeOpacity,\n            inactive: inactiveOpacity\n        };\n\n        data.setVisual('color', color);\n\n        function progress(params, data) {\n            coordSys.eachActiveState(data, function (activeState, dataIndex) {\n                var opacity = opacityMap[activeState];\n                if (activeState === 'normal' && data.hasItemOption) {\n                    var itemOpacity = data.getItemModel(dataIndex).get(opacityAccessPath$1, true);\n                    itemOpacity != null && (opacity = itemOpacity);\n                }\n                data.setItemVisual(dataIndex, 'opacity', opacity);\n            }, params.start, params.end);\n        }\n\n        return {progress: progress};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(parallelVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Get initial data and define sankey view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar SankeySeries = SeriesModel.extend({\n\n    type: 'series.sankey',\n\n    layoutInfo: null,\n\n    /**\n     * Init a graph data structure from data in option series\n     *\n     * @param  {Object} option  the object used to config echarts view\n     * @return {module:echarts/data/List} storage initial data\n     */\n    getInitialData: function (option) {\n        var links = option.edges || option.links;\n        var nodes = option.data || option.nodes;\n        if (nodes && links) {\n            var graph = createGraphFromNodeEdge(nodes, links, this, true);\n            return graph.data;\n        }\n    },\n\n    setNodePosition: function (dataIndex, localPosition) {\n        var dataItem = this.option.data[dataIndex];\n        dataItem.localX = localPosition[0];\n        dataItem.localY = localPosition[1];\n    },\n\n    /**\n     * Return the graphic data structure\n     *\n     * @return {module:echarts/data/Graph} graphic data structure\n     */\n    getGraph: function () {\n        return this.getData().graph;\n    },\n\n    /**\n     * Get edge data of graphic data structure\n     *\n     * @return {module:echarts/data/List} data structure of list\n     */\n    getEdgeData: function () {\n        return this.getGraph().edgeData;\n    },\n\n    /**\n     * @override\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType) {\n        // dataType === 'node' or empty do not show tooltip by default\n        if (dataType === 'edge') {\n            var params = this.getDataParams(dataIndex, dataType);\n            var rawDataOpt = params.data;\n            var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;\n            if (params.value) {\n                html += ' : ' + params.value;\n            }\n            return encodeHTML(html);\n        }\n\n        return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries);\n    },\n\n    optionUpdated: function () {\n        var option = this.option;\n        if (option.focusNodeAdjacency === true) {\n            option.focusNodeAdjacency = 'allEdges';\n        }\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'view',\n\n        layout: null,\n\n        // The position of the whole view\n        left: '5%',\n        top: '5%',\n        right: '20%',\n        bottom: '5%',\n\n        // Value can be 'vertical'\n        orient: 'horizontal',\n\n        // The dx of the node\n        nodeWidth: 20,\n\n        // The vertical distance between two nodes\n        nodeGap: 8,\n\n        // Control if the node can move or not\n        draggable: true,\n\n        // Value can be 'inEdges', 'outEdges', 'allEdges', true (the same as 'allEdges').\n        focusNodeAdjacency: false,\n\n        // The number of iterations to change the position of the node\n        layoutIterations: 32,\n\n        label: {\n            show: true,\n            position: 'right',\n            color: '#000',\n            fontSize: 12\n        },\n\n        itemStyle: {\n            borderWidth: 1,\n            borderColor: '#333'\n        },\n\n        lineStyle: {\n            color: '#314656',\n            opacity: 0.2,\n            curveness: 0.5\n        },\n\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                opacity: 0.6\n            }\n        },\n\n        animationEasing: 'linear',\n\n        animationDuration: 1000\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  The file used to draw sankey view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nvar nodeOpacityPath$1 = ['itemStyle', 'opacity'];\nvar lineOpacityPath$1 = ['lineStyle', 'opacity'];\n\nfunction getItemOpacity$1(item, opacityPath) {\n    return item.getVisual('opacity') || item.getModel().get(opacityPath);\n}\n\nfunction fadeOutItem$1(item, opacityPath, opacityRatio) {\n    var el = item.getGraphicEl();\n\n    var opacity = getItemOpacity$1(item, opacityPath);\n    if (opacityRatio != null) {\n        opacity == null && (opacity = 1);\n        opacity *= opacityRatio;\n    }\n\n    el.downplay && el.downplay();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nfunction fadeInItem$1(item, opacityPath) {\n    var opacity = getItemOpacity$1(item, opacityPath);\n    var el = item.getGraphicEl();\n\n    el.highlight && el.highlight();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nvar SankeyShape = extendShape({\n    shape: {\n        x1: 0, y1: 0,\n        x2: 0, y2: 0,\n        cpx1: 0, cpy1: 0,\n        cpx2: 0, cpy2: 0,\n        extent: 0,\n        orient: ''\n    },\n\n    buildPath: function (ctx, shape) {\n        var extent = shape.extent;\n        var orient = shape.orient;\n        if (orient === 'vertical') {\n            ctx.moveTo(shape.x1, shape.y1);\n            ctx.bezierCurveTo(\n                shape.cpx1, shape.cpy1,\n                shape.cpx2, shape.cpy2,\n                shape.x2, shape.y2\n            );\n            ctx.lineTo(shape.x2 + extent, shape.y2);\n            ctx.bezierCurveTo(\n                shape.cpx2 + extent, shape.cpy2,\n                shape.cpx1 + extent, shape.cpy1,\n                shape.x1 + extent, shape.y1\n            );\n        }\n        else {\n            ctx.moveTo(shape.x1, shape.y1);\n            ctx.bezierCurveTo(\n                shape.cpx1, shape.cpy1,\n                shape.cpx2, shape.cpy2,\n                shape.x2, shape.y2\n            );\n            ctx.lineTo(shape.x2, shape.y2 + extent);\n            ctx.bezierCurveTo(\n                shape.cpx2, shape.cpy2 + extent,\n                shape.cpx1, shape.cpy1 + extent,\n                shape.x1, shape.y1 + extent\n            );\n        }\n        ctx.closePath();\n    }\n});\n\nextendChartView({\n\n    type: 'sankey',\n\n    /**\n     * @private\n     * @type {module:echarts/chart/sankey/SankeySeries}\n     */\n    _model: null,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _focusAdjacencyDisabled: false,\n\n    render: function (seriesModel, ecModel, api) {\n        var sankeyView = this;\n        var graph = seriesModel.getGraph();\n        var group = this.group;\n        var layoutInfo = seriesModel.layoutInfo;\n        // view width\n        var width = layoutInfo.width;\n        // view height\n        var height = layoutInfo.height;\n        var nodeData = seriesModel.getData();\n        var edgeData = seriesModel.getData('edge');\n        var orient = seriesModel.get('orient');\n\n        this._model = seriesModel;\n\n        group.removeAll();\n\n        group.attr('position', [layoutInfo.x, layoutInfo.y]);\n\n        // generate a bezire Curve for each edge\n        graph.eachEdge(function (edge) {\n            var curve = new SankeyShape();\n            curve.dataIndex = edge.dataIndex;\n            curve.seriesIndex = seriesModel.seriesIndex;\n            curve.dataType = 'edge';\n            var lineStyleModel = edge.getModel('lineStyle');\n            var curvature = lineStyleModel.get('curveness');\n            var n1Layout = edge.node1.getLayout();\n            var node1Model = edge.node1.getModel();\n            var dragX1 = node1Model.get('localX');\n            var dragY1 = node1Model.get('localY');\n            var n2Layout = edge.node2.getLayout();\n            var node2Model = edge.node2.getModel();\n            var dragX2 = node2Model.get('localX');\n            var dragY2 = node2Model.get('localY');\n            var edgeLayout = edge.getLayout();\n            var x1;\n            var y1;\n            var x2;\n            var y2;\n            var cpx1;\n            var cpy1;\n            var cpx2;\n            var cpy2;\n\n            curve.shape.extent = Math.max(1, edgeLayout.dy);\n            curve.shape.orient = orient;\n\n            if (orient === 'vertical') {\n                x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + edgeLayout.sy;\n                y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + n1Layout.dy;\n                x2 = (dragX2 != null ? dragX2 * width : n2Layout.x) + edgeLayout.ty;\n                y2 = dragY2 != null ? dragY2 * height : n2Layout.y;\n                cpx1 = x1;\n                cpy1 = y1 * (1 - curvature) + y2 * curvature;\n                cpx2 = x2;\n                cpy2 = y1 * curvature + y2 * (1 - curvature);\n            }\n            else {\n                x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + n1Layout.dx;\n                y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + edgeLayout.sy;\n                x2 = dragX2 != null ? dragX2 * width : n2Layout.x;\n                y2 = (dragY2 != null ? dragY2 * height : n2Layout.y) + edgeLayout.ty;\n                cpx1 = x1 * (1 - curvature) + x2 * curvature;\n                cpy1 = y1;\n                cpx2 = x1 * curvature + x2 * (1 - curvature);\n                cpy2 = y2;\n            }\n\n            curve.setShape({\n                x1: x1,\n                y1: y1,\n                x2: x2,\n                y2: y2,\n                cpx1: cpx1,\n                cpy1: cpy1,\n                cpx2: cpx2,\n                cpy2: cpy2\n            });\n\n            curve.setStyle(lineStyleModel.getItemStyle());\n            // Special color, use source node color or target node color\n            switch (curve.style.fill) {\n                case 'source':\n                    curve.style.fill = edge.node1.getVisual('color');\n                    break;\n                case 'target':\n                    curve.style.fill = edge.node2.getVisual('color');\n                    break;\n            }\n\n            setHoverStyle(curve, edge.getModel('emphasis.lineStyle').getItemStyle());\n\n            group.add(curve);\n\n            edgeData.setItemGraphicEl(edge.dataIndex, curve);\n        });\n\n        // Generate a rect for each node\n        graph.eachNode(function (node) {\n            var layout = node.getLayout();\n            var itemModel = node.getModel();\n            var dragX = itemModel.get('localX');\n            var dragY = itemModel.get('localY');\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n\n            var rect = new Rect({\n                shape: {\n                    x: dragX != null ? dragX * width : layout.x,\n                    y: dragY != null ? dragY * height : layout.y,\n                    width: layout.dx,\n                    height: layout.dy\n                },\n                style: itemModel.getModel('itemStyle').getItemStyle()\n            });\n\n            var hoverStyle = node.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                rect.style, hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: seriesModel,\n                    labelDataIndex: node.dataIndex,\n                    defaultText: node.id,\n                    isRectText: true\n                }\n            );\n\n            rect.setStyle('fill', node.getVisual('color'));\n\n            setHoverStyle(rect, hoverStyle);\n\n            group.add(rect);\n\n            nodeData.setItemGraphicEl(node.dataIndex, rect);\n\n            rect.dataType = 'node';\n        });\n\n        nodeData.eachItemGraphicEl(function (el, dataIndex) {\n            var itemModel = nodeData.getItemModel(dataIndex);\n            if (itemModel.get('draggable')) {\n                el.drift = function (dx, dy) {\n                    sankeyView._focusAdjacencyDisabled = true;\n                    this.shape.x += dx;\n                    this.shape.y += dy;\n                    this.dirty();\n                    api.dispatchAction({\n                        type: 'dragNode',\n                        seriesId: seriesModel.id,\n                        dataIndex: nodeData.getRawIndex(dataIndex),\n                        localX: this.shape.x / width,\n                        localY: this.shape.y / height\n                    });\n                };\n                el.ondragend = function () {\n                    sankeyView._focusAdjacencyDisabled = false;\n                };\n                el.draggable = true;\n                el.cursor = 'move';\n            }\n\n            if (itemModel.get('focusNodeAdjacency')) {\n                el.off('mouseover').on('mouseover', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'focusNodeAdjacency',\n                            seriesId: seriesModel.id,\n                            dataIndex: el.dataIndex\n                        });\n                    }\n                });\n                el.off('mouseout').on('mouseout', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'unfocusNodeAdjacency',\n                            seriesId: seriesModel.id\n                        });\n                    }\n                });\n            }\n        });\n\n        edgeData.eachItemGraphicEl(function (el, dataIndex) {\n            var edgeModel = edgeData.getItemModel(dataIndex);\n            if (edgeModel.get('focusNodeAdjacency')) {\n                el.off('mouseover').on('mouseover', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'focusNodeAdjacency',\n                            seriesId: seriesModel.id,\n                            edgeDataIndex: el.dataIndex\n                        });\n                    }\n                });\n                el.off('mouseout').on('mouseout', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'unfocusNodeAdjacency',\n                            seriesId: seriesModel.id\n                        });\n                    }\n                });\n            }\n        });\n\n        if (!this._data && seriesModel.get('animation')) {\n            group.setClipPath(createGridClipShape$2(group.getBoundingRect(), seriesModel, function () {\n                group.removeClipPath();\n            }));\n        }\n\n        this._data = seriesModel.getData();\n    },\n\n    dispose: function () {},\n\n    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var data = this._model.getData();\n        var graph = data.graph;\n        var dataIndex = payload.dataIndex;\n        var itemModel = data.getItemModel(dataIndex);\n        var edgeDataIndex = payload.edgeDataIndex;\n\n        if (dataIndex == null && edgeDataIndex == null) {\n            return;\n        }\n        var node = graph.getNodeByIndex(dataIndex);\n        var edge = graph.getEdgeByIndex(edgeDataIndex);\n\n        graph.eachNode(function (node) {\n            fadeOutItem$1(node, nodeOpacityPath$1, 0.1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem$1(edge, lineOpacityPath$1, 0.1);\n        });\n\n        if (node) {\n            fadeInItem$1(node, nodeOpacityPath$1);\n            var focusNodeAdj = itemModel.get('focusNodeAdjacency');\n            if (focusNodeAdj === 'outEdges') {\n                each$1(node.outEdges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node2, nodeOpacityPath$1);\n                });\n            }\n            else if (focusNodeAdj === 'inEdges') {\n                each$1(node.inEdges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node1, nodeOpacityPath$1);\n                });\n            }\n            else if (focusNodeAdj === 'allEdges') {\n                each$1(node.edges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node1, nodeOpacityPath$1);\n                    fadeInItem$1(edge.node2, nodeOpacityPath$1);\n                });\n            }\n        }\n        if (edge) {\n            fadeInItem$1(edge, lineOpacityPath$1);\n            fadeInItem$1(edge.node1, nodeOpacityPath$1);\n            fadeInItem$1(edge.node2, nodeOpacityPath$1);\n        }\n    },\n\n    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var graph = this._model.getGraph();\n\n        graph.eachNode(function (node) {\n            fadeOutItem$1(node, nodeOpacityPath$1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem$1(edge, lineOpacityPath$1);\n        });\n    }\n});\n\n// Add animation to the view\nfunction createGridClipShape$2(rect, seriesModel, cb) {\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x - 10,\n            y: rect.y - 10,\n            width: 0,\n            height: rect.height + 20\n        }\n    });\n    initProps(rectEl, {\n        shape: {\n            width: rect.width + 20,\n            height: rect.height + 20\n        }\n    }, seriesModel, cb);\n\n    return rectEl;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file The interactive action of sankey view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nregisterAction({\n    type: 'dragNode',\n    event: 'dragNode',\n    // here can only use 'update' now, other value is not support in echarts.\n    update: 'update'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'sankey', query: payload}, function (seriesModel) {\n        seriesModel.setNodePosition(payload.dataIndex, [payload.localX, payload.localY]);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* The implementation references to d3.js. The use of the source\n* code of this file is also subject to the terms and consitions\n* of its license (BSD-3Clause, see <echarts/src/licenses/LICENSE-d3>).\n*/\n\n\n/**\n * nest helper used to group by the array.\n * can specified the keys and sort the keys.\n */\nfunction nest() {\n\n    var keysFunction = [];\n    var sortKeysFunction = [];\n\n    /**\n     * map an Array into the mapObject.\n     * @param {Array} array\n     * @param {number} depth\n     */\n    function map$$1(array, depth) {\n        if (depth >= keysFunction.length) {\n            return array;\n        }\n        var i = -1;\n        var n = array.length;\n        var keyFunction = keysFunction[depth++];\n        var mapObject = {};\n        var valuesByKey = {};\n\n        while (++i < n) {\n            var keyValue = keyFunction(array[i]);\n            var values = valuesByKey[keyValue];\n\n            if (values) {\n                values.push(array[i]);\n            }\n            else {\n                valuesByKey[keyValue] = [array[i]];\n            }\n        }\n\n        each$1(valuesByKey, function (value, key) {\n            mapObject[key] = map$$1(value, depth);\n        });\n\n        return mapObject;\n    }\n\n    /**\n     * transform the Map Object to multidimensional Array\n     * @param {Object} map\n     * @param {number} depth\n     */\n    function entriesMap(mapObject, depth) {\n        if (depth >= keysFunction.length) {\n            return mapObject;\n        }\n        var array = [];\n        var sortKeyFunction = sortKeysFunction[depth++];\n\n        each$1(mapObject, function (value, key) {\n            array.push({\n                key: key, values: entriesMap(value, depth)\n            });\n        });\n\n        if (sortKeyFunction) {\n            return array.sort(function (a, b) {\n                return sortKeyFunction(a.key, b.key);\n            });\n        }\n\n        return array;\n    }\n\n    return {\n        /**\n         * specified the key to groupby the arrays.\n         * users can specified one more keys.\n         * @param {Function} d\n         */\n        key: function (d) {\n            keysFunction.push(d);\n            return this;\n        },\n\n        /**\n         * specified the comparator to sort the keys\n         * @param {Function} order\n         */\n        sortKeys: function (order) {\n            sortKeysFunction[keysFunction.length - 1] = order;\n            return this;\n        },\n\n        /**\n         * the array to be grouped by.\n         * @param {Array} array\n         */\n        entries: function (array) {\n            return entriesMap(map$$1(array, 0), 0);\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file The layout algorithm of sankey view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar sankeyLayout = function (ecModel, api, payload) {\n\n    ecModel.eachSeriesByType('sankey', function (seriesModel) {\n\n        var nodeWidth = seriesModel.get('nodeWidth');\n        var nodeGap = seriesModel.get('nodeGap');\n\n        var layoutInfo = getViewRect$3(seriesModel, api);\n\n        seriesModel.layoutInfo = layoutInfo;\n\n        var width = layoutInfo.width;\n        var height = layoutInfo.height;\n\n        var graph = seriesModel.getGraph();\n\n        var nodes = graph.nodes;\n        var edges = graph.edges;\n\n        computeNodeValues(nodes);\n\n        var filteredNodes = filter(nodes, function (node) {\n            return node.getLayout().value === 0;\n        });\n\n        var iterations = filteredNodes.length !== 0\n            ? 0 : seriesModel.get('layoutIterations');\n\n        var orient = seriesModel.get('orient');\n\n        layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient);\n    });\n};\n\n/**\n * Get the layout position of the whole view\n *\n * @param {module:echarts/model/Series} seriesModel  the model object of sankey series\n * @param {module:echarts/ExtensionAPI} api  provide the API list that the developer can call\n * @return {module:zrender/core/BoundingRect}  size of rect to draw the sankey view\n */\nfunction getViewRect$3(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\nfunction layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient) {\n    computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient);\n    computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient);\n    computeEdgeDepths(nodes, orient);\n}\n\n/**\n * Compute the value of each node by summing the associated edge's value\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n */\nfunction computeNodeValues(nodes) {\n    each$1(nodes, function (node) {\n        var value1 = sum(node.outEdges, getEdgeValue);\n        var value2 = sum(node.inEdges, getEdgeValue);\n        var value = Math.max(value1, value2);\n        node.setLayout({value: value}, true);\n    });\n}\n\n/**\n * Compute the x-position for each node.\n *\n * Here we use Kahn algorithm to detect cycle when we traverse\n * the node to computer the initial x position.\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param  {number} nodeWidth  the dx of the node\n * @param  {number} width  the whole width of the area to draw the view\n */\nfunction computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient) {\n    // Used to mark whether the edge is deleted. if it is deleted,\n    // the value is 0, otherwise it is 1.\n    var remainEdges = [];\n\n    // Storage each node's indegree.\n    var indegreeArr = [];\n\n    //Used to storage the node with indegree is equal to 0.\n    var zeroIndegrees = [];\n\n    var nextNode = [];\n    var x = 0;\n    var kx = 0;\n\n    for (var i = 0; i < edges.length; i++) {\n        remainEdges[i] = 1;\n    }\n\n    for (i = 0; i < nodes.length; i++) {\n        indegreeArr[i] = nodes[i].inEdges.length;\n        if (indegreeArr[i] === 0) {\n            zeroIndegrees.push(nodes[i]);\n        }\n    }\n\n    while (zeroIndegrees.length) {\n        for (var idx = 0; idx < zeroIndegrees.length; idx++) {\n            var node = zeroIndegrees[idx];\n            if (orient === 'vertical') {\n                node.setLayout({y: x}, true);\n                node.setLayout({dy: nodeWidth}, true);\n            }\n            else {\n                node.setLayout({x: x}, true);\n                node.setLayout({dx: nodeWidth}, true);\n            }\n            for (var oidx = 0; oidx < node.outEdges.length; oidx++) {\n                var edge = node.outEdges[oidx];\n                var indexEdge = edges.indexOf(edge);\n                remainEdges[indexEdge] = 0;\n                var targetNode = edge.node2;\n                var nodeIndex = nodes.indexOf(targetNode);\n                if (--indegreeArr[nodeIndex] === 0) {\n                    nextNode.push(targetNode);\n                }\n            }\n        }\n        ++x;\n        zeroIndegrees = nextNode;\n        nextNode = [];\n    }\n\n    for (i = 0; i < remainEdges.length; i++) {\n        if (__DEV__) {\n            if (remainEdges[i] === 1) {\n                throw new Error('Sankey is a DAG, the original data has cycle!');\n            }\n        }\n    }\n\n    moveSinksRight(nodes, x, orient);\n\n    if (orient === 'vertical') {\n        kx = (height - nodeWidth) / (x - 1);\n    }\n    else {\n        kx = (width - nodeWidth) / (x - 1);\n    }\n    scaleNodeBreadths(nodes, kx, orient);\n}\n\n/**\n * All the node without outEgdes are assigned maximum x-position and\n *     be aligned in the last column.\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {number} x  value (x-1) use to assign to node without outEdges\n *     as x-position\n */\nfunction moveSinksRight(nodes, x, orient) {\n    each$1(nodes, function (node) {\n        if (!node.outEdges.length) {\n            if (orient === 'vertical') {\n                node.setLayout({y: x - 1}, true);\n            }\n            else {\n                node.setLayout({x: x - 1}, true);\n            }\n        }\n    });\n}\n\n/**\n * Scale node x-position to the width\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {number} kx   multiple used to scale nodes\n */\nfunction scaleNodeBreadths(nodes, kx, orient) {\n    each$1(nodes, function (node) {\n        if (orient === 'vertical') {\n            var nodeY = node.getLayout().y * kx;\n            node.setLayout({y: nodeY}, true);\n        }\n        else {\n            var nodeX = node.getLayout().x * kx;\n            node.setLayout({x: nodeX}, true);\n        }\n    });\n}\n\n/**\n * Using Gauss-Seidel iterations method to compute the node depth(y-position)\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {module:echarts/data/Graph~Edge} edges  edge of sankey view\n * @param {number} height  the whole height of the area to draw the view\n * @param {number} nodeGap  the vertical distance between two nodes\n *     in the same column.\n * @param {number} iterations  the number of iterations for the algorithm\n */\nfunction computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient) {\n    var nodesByBreadth = nest()\n        .key(getKeyFunction(orient))\n        .sortKeys(function (a, b) {\n            return a - b;\n        })\n        .entries(nodes)\n        .map(function (d) {\n            return d.values;\n        });\n\n    initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient);\n    resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n\n    for (var alpha = 1; iterations > 0; iterations--) {\n        // 0.99 is a experience parameter, ensure that each iterations of\n        // changes as small as possible.\n        alpha *= 0.99;\n        relaxRightToLeft(nodesByBreadth, alpha, orient);\n        resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n        relaxLeftToRight(nodesByBreadth, alpha, orient);\n        resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n    }\n}\n\nfunction getKeyFunction(orient) {\n    if (orient === 'vertical') {\n        return function (d) {\n            return d.getLayout().y;\n        };\n    }\n    return function (d) {\n        return d.getLayout().x;\n    };\n}\n\n/**\n * Compute the original y-position for each node\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the nodes x-position.\n * @param {module:echarts/data/Graph~Edge} edges  edge of sankey view\n * @param {number} height  the whole height of the area to draw the view\n * @param {number} nodeGap  the vertical distance between two nodes\n */\nfunction initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient) {\n    var kyArray = [];\n    each$1(nodesByBreadth, function (nodes) {\n        var n = nodes.length;\n        var sum = 0;\n        var ky = 0;\n        each$1(nodes, function (node) {\n            sum += node.getLayout().value;\n        });\n        if (orient === 'vertical') {\n            ky = (width - (n - 1) * nodeGap) / sum;\n        }\n        else {\n            ky = (height - (n - 1) * nodeGap) / sum;\n        }\n        kyArray.push(ky);\n    });\n\n    kyArray.sort(function (a, b) {\n        return a - b;\n    });\n    var ky0 = kyArray[0];\n\n    each$1(nodesByBreadth, function (nodes) {\n        each$1(nodes, function (node, i) {\n            var nodeDy = node.getLayout().value * ky0;\n            if (orient === 'vertical') {\n                node.setLayout({x: i}, true);\n                node.setLayout({dx: nodeDy}, true);\n            }\n            else {\n                node.setLayout({y: i}, true);\n                node.setLayout({dy: nodeDy}, true);\n            }\n\n        });\n    });\n\n    each$1(edges, function (edge) {\n        var edgeDy = +edge.getValue() * ky0;\n        edge.setLayout({dy: edgeDy}, true);\n    });\n}\n\n/**\n * Resolve the collision of initialized depth (y-position)\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the nodes x-position.\n * @param {number} nodeGap  the vertical distance between two nodes\n * @param {number} height  the whole height of the area to draw the view\n */\nfunction resolveCollisions(nodesByBreadth, nodeGap, height, width, orient) {\n    each$1(nodesByBreadth, function (nodes) {\n        var node;\n        var dy;\n        var y0 = 0;\n        var n = nodes.length;\n        var i;\n\n        if (orient === 'vertical') {\n            var nodeX;\n            nodes.sort(function (a, b) {\n                return a.getLayout().x - b.getLayout().x;\n            });\n            for (i = 0; i < n; i++) {\n                node = nodes[i];\n                dy = y0 - node.getLayout().x;\n                if (dy > 0) {\n                    nodeX = node.getLayout().x + dy;\n                    node.setLayout({x: nodeX}, true);\n                }\n                y0 = node.getLayout().x + node.getLayout().dx + nodeGap;\n            }\n            // If the bottommost node goes outside the bounds, push it back up\n            dy = y0 - nodeGap - width;\n            if (dy > 0) {\n                nodeX = node.getLayout().x - dy;\n                node.setLayout({x: nodeX}, true);\n                y0 = nodeX;\n                for (i = n - 2; i >= 0; --i) {\n                    node = nodes[i];\n                    dy = node.getLayout().x + node.getLayout().dx + nodeGap - y0;\n                    if (dy > 0) {\n                        nodeX = node.getLayout().x - dy;\n                        node.setLayout({x: nodeX}, true);\n                    }\n                    y0 = node.getLayout().x;\n                }\n            }\n        }\n        else {\n            var nodeY;\n            nodes.sort(function (a, b) {\n                return a.getLayout().y - b.getLayout().y;\n            });\n            for (i = 0; i < n; i++) {\n                node = nodes[i];\n                dy = y0 - node.getLayout().y;\n                if (dy > 0) {\n                    nodeY = node.getLayout().y + dy;\n                    node.setLayout({y: nodeY}, true);\n                }\n                y0 = node.getLayout().y + node.getLayout().dy + nodeGap;\n            }\n            // If the bottommost node goes outside the bounds, push it back up\n            dy = y0 - nodeGap - height;\n            if (dy > 0) {\n                nodeY = node.getLayout().y - dy;\n                node.setLayout({y: nodeY}, true);\n                y0 = nodeY;\n                for (i = n - 2; i >= 0; --i) {\n                    node = nodes[i];\n                    dy = node.getLayout().y + node.getLayout().dy + nodeGap - y0;\n                    if (dy > 0) {\n                        nodeY = node.getLayout().y - dy;\n                        node.setLayout({y: nodeY}, true);\n                    }\n                    y0 = node.getLayout().y;\n                }\n            }\n        }\n    });\n}\n\n/**\n * Change the y-position of the nodes, except most the right side nodes\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the node x-position.\n * @param {number} alpha  parameter used to adjust the nodes y-position\n */\nfunction relaxRightToLeft(nodesByBreadth, alpha, orient) {\n    each$1(nodesByBreadth.slice().reverse(), function (nodes) {\n        each$1(nodes, function (node) {\n            if (node.outEdges.length) {\n                var y = sum(node.outEdges, weightedTarget, orient) / sum(node.outEdges, getEdgeValue, orient);\n                if (orient === 'vertical') {\n                    var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({x: nodeX}, true);\n                }\n                else {\n                    var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({y: nodeY}, true);\n                }\n            }\n        });\n    });\n}\n\nfunction weightedTarget(edge, orient) {\n    return center$1(edge.node2, orient) * edge.getValue();\n}\n\nfunction weightedSource(edge, orient) {\n    return center$1(edge.node1, orient) * edge.getValue();\n}\n\nfunction center$1(node, orient) {\n    if (orient === 'vertical') {\n        return node.getLayout().x + node.getLayout().dx / 2;\n    }\n    return node.getLayout().y + node.getLayout().dy / 2;\n}\n\nfunction getEdgeValue(edge) {\n    return edge.getValue();\n}\n\nfunction sum(array, f, orient) {\n    var sum = 0;\n    var len = array.length;\n    var i = -1;\n    while (++i < len) {\n        var value = +f.call(array, array[i], orient);\n        if (!isNaN(value)) {\n            sum += value;\n        }\n    }\n    return sum;\n}\n\n/**\n * Change the y-position of the nodes, except most the left side nodes\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the node x-position.\n * @param {number} alpha  parameter used to adjust the nodes y-position\n */\nfunction relaxLeftToRight(nodesByBreadth, alpha, orient) {\n    each$1(nodesByBreadth, function (nodes) {\n        each$1(nodes, function (node) {\n            if (node.inEdges.length) {\n                var y = sum(node.inEdges, weightedSource, orient) / sum(node.inEdges, getEdgeValue, orient);\n                if (orient === 'vertical') {\n                    var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({x: nodeX}, true);\n                }\n                else {\n                    var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({y: nodeY}, true);\n                }\n            }\n        });\n    });\n}\n\n/**\n * Compute the depth(y-position) of each edge\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n */\nfunction computeEdgeDepths(nodes, orient) {\n    each$1(nodes, function (node) {\n        if (orient === 'vertical') {\n            node.outEdges.sort(function (a, b) {\n                return a.node2.getLayout().x - b.node2.getLayout().x;\n            });\n            node.inEdges.sort(function (a, b) {\n                return a.node1.getLayout().x - b.node1.getLayout().x;\n            });\n        }\n        else {\n            node.outEdges.sort(function (a, b) {\n                return a.node2.getLayout().y - b.node2.getLayout().y;\n            });\n            node.inEdges.sort(function (a, b) {\n                return a.node1.getLayout().y - b.node1.getLayout().y;\n            });\n        }\n    });\n    each$1(nodes, function (node) {\n        var sy = 0;\n        var ty = 0;\n        each$1(node.outEdges, function (edge) {\n            edge.setLayout({sy: sy}, true);\n            sy += edge.getLayout().dy;\n        });\n        each$1(node.inEdges, function (edge) {\n            edge.setLayout({ty: ty}, true);\n            ty += edge.getLayout().dy;\n        });\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual encoding for sankey view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nvar sankeyVisual = function (ecModel, payload) {\n    ecModel.eachSeriesByType('sankey', function (seriesModel) {\n        var graph = seriesModel.getGraph();\n        var nodes = graph.nodes;\n        if (nodes.length) {\n            var minValue = Infinity;\n            var maxValue = -Infinity;\n            each$1(nodes, function (node) {\n                var nodeValue = node.getLayout().value;\n                if (nodeValue < minValue) {\n                    minValue = nodeValue;\n                }\n                if (nodeValue > maxValue) {\n                    maxValue = nodeValue;\n                }\n            });\n\n            each$1(nodes, function (node) {\n                var mapping = new VisualMapping({\n                    type: 'color',\n                    mappingMethod: 'linear',\n                    dataExtent: [minValue, maxValue],\n                    visual: seriesModel.get('color')\n                });\n\n                var mapValueToColor = mapping.mapValueToVisual(node.getLayout().value);\n                node.setVisual('color', mapValueToColor);\n                // If set itemStyle.normal.color\n                var itemModel = node.getModel();\n                var customColor = itemModel.get('itemStyle.color');\n                if (customColor != null) {\n                    node.setVisual('color', customColor);\n                }\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(sankeyLayout);\nregisterVisual(sankeyVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar seriesModelMixin = {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    _baseAxisDim: null,\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        // When both types of xAxis and yAxis are 'value', layout is\n        // needed to be specified by user. Otherwise, layout can be\n        // judged by which axis is category.\n\n        var ordinalMeta;\n\n        var xAxisModel = ecModel.getComponent('xAxis', this.get('xAxisIndex'));\n        var yAxisModel = ecModel.getComponent('yAxis', this.get('yAxisIndex'));\n        var xAxisType = xAxisModel.get('type');\n        var yAxisType = yAxisModel.get('type');\n        var addOrdinal;\n\n        // FIXME\n        // 考虑时间轴\n\n        if (xAxisType === 'category') {\n            option.layout = 'horizontal';\n            ordinalMeta = xAxisModel.getOrdinalMeta();\n            addOrdinal = true;\n        }\n        else if (yAxisType === 'category') {\n            option.layout = 'vertical';\n            ordinalMeta = yAxisModel.getOrdinalMeta();\n            addOrdinal = true;\n        }\n        else {\n            option.layout = option.layout || 'horizontal';\n        }\n\n        var coordDims = ['x', 'y'];\n        var baseAxisDimIndex = option.layout === 'horizontal' ? 0 : 1;\n        var baseAxisDim = this._baseAxisDim = coordDims[baseAxisDimIndex];\n        var otherAxisDim = coordDims[1 - baseAxisDimIndex];\n        var axisModels = [xAxisModel, yAxisModel];\n        var baseAxisType = axisModels[baseAxisDimIndex].get('type');\n        var otherAxisType = axisModels[1 - baseAxisDimIndex].get('type');\n        var data = option.data;\n\n        // ??? FIXME make a stage to perform data transfrom.\n        // MUST create a new data, consider setOption({}) again.\n        if (data && addOrdinal) {\n            var newOptionData = [];\n            each$1(data, function (item, index) {\n                var newItem;\n                if (item.value && isArray(item.value)) {\n                    newItem = item.value.slice();\n                    item.value.unshift(index);\n                }\n                else if (isArray(item)) {\n                    newItem = item.slice();\n                    item.unshift(index);\n                }\n                else {\n                    newItem = item;\n                }\n                newOptionData.push(newItem);\n            });\n            option.data = newOptionData;\n        }\n\n        var defaultValueDimensions = this.defaultValueDimensions;\n\n        return createListSimply(\n            this,\n            {\n                coordDimensions: [{\n                    name: baseAxisDim,\n                    type: getDimensionTypeByAxis(baseAxisType),\n                    ordinalMeta: ordinalMeta,\n                    otherDims: {\n                        tooltip: false,\n                        itemName: 0\n                    },\n                    dimsDef: ['base']\n                }, {\n                    name: otherAxisDim,\n                    type: getDimensionTypeByAxis(otherAxisType),\n                    dimsDef: defaultValueDimensions.slice()\n                }],\n                dimensionsCount: defaultValueDimensions.length + 1\n            }\n        );\n    },\n\n    /**\n     * If horizontal, base axis is x, otherwise y.\n     * @override\n     */\n    getBaseAxis: function () {\n        var dim = this._baseAxisDim;\n        return this.ecModel.getComponent(dim + 'Axis', this.get(dim + 'AxisIndex')).axis;\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BoxplotSeries = SeriesModel.extend({\n\n    type: 'series.boxplot',\n\n    dependencies: ['xAxis', 'yAxis', 'grid'],\n\n    // TODO\n    // box width represents group size, so dimension should have 'size'.\n\n    /**\n     * @see <https://en.wikipedia.org/wiki/Box_plot>\n     * The meanings of 'min' and 'max' depend on user,\n     * and echarts do not need to know it.\n     * @readOnly\n     */\n    defaultValueDimensions: [\n        {name: 'min', defaultTooltip: true},\n        {name: 'Q1', defaultTooltip: true},\n        {name: 'median', defaultTooltip: true},\n        {name: 'Q3', defaultTooltip: true},\n        {name: 'max', defaultTooltip: true}\n    ],\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * @override\n     */\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        layout: null,               // 'horizontal' or 'vertical'\n        boxWidth: [7, 50],       // [min, max] can be percent of band width.\n\n        itemStyle: {\n            color: '#fff',\n            borderWidth: 1\n        },\n\n        emphasis: {\n            itemStyle: {\n                borderWidth: 2,\n                shadowBlur: 5,\n                shadowOffsetX: 2,\n                shadowOffsetY: 2,\n                shadowColor: 'rgba(0,0,0,0.4)'\n            }\n        },\n\n        animationEasing: 'elasticOut',\n        animationDuration: 800\n    }\n});\n\nmixin(BoxplotSeries, seriesModelMixin, true);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Update common properties\nvar NORMAL_ITEM_STYLE_PATH = ['itemStyle'];\nvar EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'];\n\nvar BoxplotView = Chart.extend({\n\n    type: 'boxplot',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var group = this.group;\n        var oldData = this._data;\n\n        // There is no old data only when first rendering or switching from\n        // stream mode to normal mode, where previous elements should be removed.\n        if (!this._data) {\n            group.removeAll();\n        }\n\n        var constDim = seriesModel.get('layout') === 'horizontal' ? 1 : 0;\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (data.hasValue(newIdx)) {\n                    var itemLayout = data.getItemLayout(newIdx);\n                    var symbolEl = createNormalBox(itemLayout, data, newIdx, constDim, true);\n                    data.setItemGraphicEl(newIdx, symbolEl);\n                    group.add(symbolEl);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n\n                // Empty data\n                if (!data.hasValue(newIdx)) {\n                    group.remove(symbolEl);\n                    return;\n                }\n\n                var itemLayout = data.getItemLayout(newIdx);\n                if (!symbolEl) {\n                    symbolEl = createNormalBox(itemLayout, data, newIdx, constDim);\n                }\n                else {\n                    updateNormalBoxData(itemLayout, symbolEl, data, newIdx);\n                }\n\n                group.add(symbolEl);\n\n                data.setItemGraphicEl(newIdx, symbolEl);\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        this._data = null;\n        data && data.eachItemGraphicEl(function (el) {\n            el && group.remove(el);\n        });\n    },\n\n    dispose: noop\n\n});\n\n\nvar BoxPath = Path.extend({\n\n    type: 'boxplotBoxPath',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        var ends = shape.points;\n\n        var i = 0;\n        ctx.moveTo(ends[i][0], ends[i][1]);\n        i++;\n        for (; i < 4; i++) {\n            ctx.lineTo(ends[i][0], ends[i][1]);\n        }\n        ctx.closePath();\n\n        for (; i < ends.length; i++) {\n            ctx.moveTo(ends[i][0], ends[i][1]);\n            i++;\n            ctx.lineTo(ends[i][0], ends[i][1]);\n        }\n    }\n});\n\n\nfunction createNormalBox(itemLayout, data, dataIndex, constDim, isInit) {\n    var ends = itemLayout.ends;\n\n    var el = new BoxPath({\n        shape: {\n            points: isInit\n                ? transInit(ends, constDim, itemLayout)\n                : ends\n        }\n    });\n\n    updateNormalBoxData(itemLayout, el, data, dataIndex, isInit);\n\n    return el;\n}\n\nfunction updateNormalBoxData(itemLayout, el, data, dataIndex, isInit) {\n    var seriesModel = data.hostModel;\n    var updateMethod = graphic[isInit ? 'initProps' : 'updateProps'];\n\n    updateMethod(\n        el,\n        {shape: {points: itemLayout.ends}},\n        seriesModel,\n        dataIndex\n    );\n\n    var itemModel = data.getItemModel(dataIndex);\n    var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH);\n    var borderColor = data.getItemVisual(dataIndex, 'color');\n\n    // Exclude borderColor.\n    var itemStyle = normalItemStyleModel.getItemStyle(['borderColor']);\n    itemStyle.stroke = borderColor;\n    itemStyle.strokeNoScale = true;\n    el.useStyle(itemStyle);\n\n    el.z2 = 100;\n\n    var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();\n    setHoverStyle(el, hoverStyle);\n}\n\nfunction transInit(points, dim, itemLayout) {\n    return map(points, function (point) {\n        point = point.slice();\n        point[dim] = itemLayout.initBaseline;\n        return point;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar borderColorQuery = ['itemStyle', 'borderColor'];\n\nvar boxplotVisual = function (ecModel, api) {\n\n    var globalColors = ecModel.get('color');\n\n    ecModel.eachRawSeriesByType('boxplot', function (seriesModel) {\n\n        var defaulColor = globalColors[seriesModel.seriesIndex % globalColors.length];\n        var data = seriesModel.getData();\n\n        data.setVisual({\n            legendSymbol: 'roundRect',\n            // Use name 'color' but not 'borderColor' for legend usage and\n            // visual coding from other component like dataRange.\n            color: seriesModel.get(borderColorQuery) || defaulColor\n        });\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            data.each(function (idx) {\n                var itemModel = data.getItemModel(idx);\n                data.setItemVisual(\n                    idx,\n                    {color: itemModel.get(borderColorQuery, true)}\n                );\n            });\n        }\n    });\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$13 = each$1;\n\nvar boxplotLayout = function (ecModel) {\n\n    var groupResult = groupSeriesByAxis(ecModel);\n\n    each$13(groupResult, function (groupItem) {\n        var seriesModels = groupItem.seriesModels;\n\n        if (!seriesModels.length) {\n            return;\n        }\n\n        calculateBase(groupItem);\n\n        each$13(seriesModels, function (seriesModel, idx) {\n            layoutSingleSeries(\n                seriesModel,\n                groupItem.boxOffsetList[idx],\n                groupItem.boxWidthList[idx]\n            );\n        });\n    });\n};\n\n/**\n * Group series by axis.\n */\nfunction groupSeriesByAxis(ecModel) {\n    var result = [];\n    var axisList = [];\n\n    ecModel.eachSeriesByType('boxplot', function (seriesModel) {\n        var baseAxis = seriesModel.getBaseAxis();\n        var idx = indexOf(axisList, baseAxis);\n\n        if (idx < 0) {\n            idx = axisList.length;\n            axisList[idx] = baseAxis;\n            result[idx] = {axis: baseAxis, seriesModels: []};\n        }\n\n        result[idx].seriesModels.push(seriesModel);\n    });\n\n    return result;\n}\n\n/**\n * Calculate offset and box width for each series.\n */\nfunction calculateBase(groupItem) {\n    var extent;\n    var baseAxis = groupItem.axis;\n    var seriesModels = groupItem.seriesModels;\n    var seriesCount = seriesModels.length;\n\n    var boxWidthList = groupItem.boxWidthList = [];\n    var boxOffsetList = groupItem.boxOffsetList = [];\n    var boundList = [];\n\n    var bandWidth;\n    if (baseAxis.type === 'category') {\n        bandWidth = baseAxis.getBandWidth();\n    }\n    else {\n        var maxDataCount = 0;\n        each$13(seriesModels, function (seriesModel) {\n            maxDataCount = Math.max(maxDataCount, seriesModel.getData().count());\n        });\n        extent = baseAxis.getExtent(),\n        Math.abs(extent[1] - extent[0]) / maxDataCount;\n    }\n\n    each$13(seriesModels, function (seriesModel) {\n        var boxWidthBound = seriesModel.get('boxWidth');\n        if (!isArray(boxWidthBound)) {\n            boxWidthBound = [boxWidthBound, boxWidthBound];\n        }\n        boundList.push([\n            parsePercent$1(boxWidthBound[0], bandWidth) || 0,\n            parsePercent$1(boxWidthBound[1], bandWidth) || 0\n        ]);\n    });\n\n    var availableWidth = bandWidth * 0.8 - 2;\n    var boxGap = availableWidth / seriesCount * 0.3;\n    var boxWidth = (availableWidth - boxGap * (seriesCount - 1)) / seriesCount;\n    var base = boxWidth / 2 - availableWidth / 2;\n\n    each$13(seriesModels, function (seriesModel, idx) {\n        boxOffsetList.push(base);\n        base += boxGap + boxWidth;\n\n        boxWidthList.push(\n            Math.min(Math.max(boxWidth, boundList[idx][0]), boundList[idx][1])\n        );\n    });\n}\n\n/**\n * Calculate points location for each series.\n */\nfunction layoutSingleSeries(seriesModel, offset, boxWidth) {\n    var coordSys = seriesModel.coordinateSystem;\n    var data = seriesModel.getData();\n    var halfWidth = boxWidth / 2;\n    var cDimIdx = seriesModel.get('layout') === 'horizontal' ? 0 : 1;\n    var vDimIdx = 1 - cDimIdx;\n    var coordDims = ['x', 'y'];\n    var cDim = data.mapDimension(coordDims[cDimIdx]);\n    var vDims = data.mapDimension(coordDims[vDimIdx], true);\n\n    if (cDim == null || vDims.length < 5) {\n        return;\n    }\n\n    for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {\n        var axisDimVal = data.get(cDim, dataIndex);\n\n        var median = getPoint(axisDimVal, vDims[2], dataIndex);\n        var end1 = getPoint(axisDimVal, vDims[0], dataIndex);\n        var end2 = getPoint(axisDimVal, vDims[1], dataIndex);\n        var end4 = getPoint(axisDimVal, vDims[3], dataIndex);\n        var end5 = getPoint(axisDimVal, vDims[4], dataIndex);\n\n        var ends = [];\n        addBodyEnd(ends, end2, 0);\n        addBodyEnd(ends, end4, 1);\n\n        ends.push(end1, end2, end5, end4);\n        layEndLine(ends, end1);\n        layEndLine(ends, end5);\n        layEndLine(ends, median);\n\n        data.setItemLayout(dataIndex, {\n            initBaseline: median[vDimIdx],\n            ends: ends\n        });\n    }\n\n    function getPoint(axisDimVal, dimIdx, dataIndex) {\n        var val = data.get(dimIdx, dataIndex);\n        var p = [];\n        p[cDimIdx] = axisDimVal;\n        p[vDimIdx] = val;\n        var point;\n        if (isNaN(axisDimVal) || isNaN(val)) {\n            point = [NaN, NaN];\n        }\n        else {\n            point = coordSys.dataToPoint(p);\n            point[cDimIdx] += offset;\n        }\n        return point;\n    }\n\n    function addBodyEnd(ends, point, start) {\n        var point1 = point.slice();\n        var point2 = point.slice();\n        point1[cDimIdx] += halfWidth;\n        point2[cDimIdx] -= halfWidth;\n        start\n            ? ends.push(point1, point2)\n            : ends.push(point2, point1);\n    }\n\n    function layEndLine(ends, endCenter) {\n        var from = endCenter.slice();\n        var to = endCenter.slice();\n        from[cDimIdx] -= halfWidth;\n        to[cDimIdx] += halfWidth;\n        ends.push(from, to);\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(boxplotVisual);\nregisterLayout(boxplotLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CandlestickSeries = SeriesModel.extend({\n\n    type: 'series.candlestick',\n\n    dependencies: ['xAxis', 'yAxis', 'grid'],\n\n    /**\n     * @readOnly\n     */\n    defaultValueDimensions: [\n        {name: 'open', defaultTooltip: true},\n        {name: 'close', defaultTooltip: true},\n        {name: 'lowest', defaultTooltip: true},\n        {name: 'highest', defaultTooltip: true}\n    ],\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * @override\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        layout: null, // 'horizontal' or 'vertical'\n\n        itemStyle: {\n            color: '#c23531', // 阳线 positive\n            color0: '#314656', // 阴线 negative     '#c23531', '#314656'\n            borderWidth: 1,\n            // FIXME\n            // ec2中使用的是lineStyle.color 和 lineStyle.color0\n            borderColor: '#c23531',\n            borderColor0: '#314656'\n        },\n\n        emphasis: {\n            itemStyle: {\n                borderWidth: 2\n            }\n        },\n\n        barMaxWidth: null,\n        barMinWidth: null,\n        barWidth: null,\n\n        large: true,\n        largeThreshold: 600,\n\n        progressive: 3e3,\n        progressiveThreshold: 1e4,\n        progressiveChunkMode: 'mod',\n\n        animationUpdate: false,\n        animationEasing: 'linear',\n        animationDuration: 300\n    },\n\n    /**\n     * Get dimension for shadow in dataZoom\n     * @return {string} dimension name\n     */\n    getShadowDim: function () {\n        return 'open';\n    },\n\n    brushSelector: function (dataIndex, data, selectors) {\n        var itemLayout = data.getItemLayout(dataIndex);\n        return itemLayout && selectors.rect(itemLayout.brushRect);\n    }\n\n});\n\nmixin(CandlestickSeries, seriesModelMixin, true);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMAL_ITEM_STYLE_PATH$1 = ['itemStyle'];\nvar EMPHASIS_ITEM_STYLE_PATH$1 = ['emphasis', 'itemStyle'];\nvar SKIP_PROPS = ['color', 'color0', 'borderColor', 'borderColor0'];\n\n\nvar CandlestickView = Chart.extend({\n\n    type: 'candlestick',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        this._isLargeDraw\n            ? this._renderLarge(seriesModel)\n            : this._renderNormal(seriesModel);\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        this._isLargeDraw\n             ? this._incrementalRenderLarge(params, seriesModel)\n             : this._incrementalRenderNormal(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel) {\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n        var isSimpleBox = data.getLayout('isSimpleBox');\n\n        // There is no old data only when first rendering or switching from\n        // stream mode to normal mode, where previous elements should be removed.\n        if (!this._data) {\n            group.removeAll();\n        }\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (data.hasValue(newIdx)) {\n                    var el;\n\n                    var itemLayout = data.getItemLayout(newIdx);\n                    el = createNormalBox$1(itemLayout, newIdx, true);\n                    initProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);\n\n                    setBoxCommon(el, data, newIdx, isSimpleBox);\n\n                    group.add(el);\n                    data.setItemGraphicEl(newIdx, el);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n\n                // Empty data\n                if (!data.hasValue(newIdx)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemLayout = data.getItemLayout(newIdx);\n                if (!el) {\n                    el = createNormalBox$1(itemLayout, newIdx);\n                }\n                else {\n                    updateProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);\n                }\n\n                setBoxCommon(el, data, newIdx, isSimpleBox);\n\n                group.add(el);\n                data.setItemGraphicEl(newIdx, el);\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel) {\n        this._clear();\n        createLarge$1(seriesModel, this.group);\n    },\n\n    _incrementalRenderNormal: function (params, seriesModel) {\n        var data = seriesModel.getData();\n        var isSimpleBox = data.getLayout('isSimpleBox');\n\n        var dataIndex;\n        while ((dataIndex = params.next()) != null) {\n            var el;\n\n            var itemLayout = data.getItemLayout(dataIndex);\n            el = createNormalBox$1(itemLayout, dataIndex);\n            setBoxCommon(el, data, dataIndex, isSimpleBox);\n\n            el.incremental = true;\n            this.group.add(el);\n        }\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge$1(seriesModel, this.group, true);\n    },\n\n    remove: function (ecModel) {\n        this._clear();\n    },\n\n    _clear: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: noop\n\n});\n\n\nvar NormalBoxPath = Path.extend({\n\n    type: 'normalCandlestickBox',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        var ends = shape.points;\n\n        if (this.__simpleBox) {\n            ctx.moveTo(ends[4][0], ends[4][1]);\n            ctx.lineTo(ends[6][0], ends[6][1]);\n        }\n        else {\n            ctx.moveTo(ends[0][0], ends[0][1]);\n            ctx.lineTo(ends[1][0], ends[1][1]);\n            ctx.lineTo(ends[2][0], ends[2][1]);\n            ctx.lineTo(ends[3][0], ends[3][1]);\n            ctx.closePath();\n\n            ctx.moveTo(ends[4][0], ends[4][1]);\n            ctx.lineTo(ends[5][0], ends[5][1]);\n            ctx.moveTo(ends[6][0], ends[6][1]);\n            ctx.lineTo(ends[7][0], ends[7][1]);\n        }\n    }\n});\n\nfunction createNormalBox$1(itemLayout, dataIndex, isInit) {\n    var ends = itemLayout.ends;\n    return new NormalBoxPath({\n        shape: {\n            points: isInit\n                ? transInit$1(ends, itemLayout)\n                : ends\n        },\n        z2: 100\n    });\n}\n\nfunction setBoxCommon(el, data, dataIndex, isSimpleBox) {\n    var itemModel = data.getItemModel(dataIndex);\n    var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH$1);\n    var color = data.getItemVisual(dataIndex, 'color');\n    var borderColor = data.getItemVisual(dataIndex, 'borderColor') || color;\n\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var itemStyle = normalItemStyleModel.getItemStyle(SKIP_PROPS);\n\n    el.useStyle(itemStyle);\n    el.style.strokeNoScale = true;\n    el.style.fill = color;\n    el.style.stroke = borderColor;\n\n    el.__simpleBox = isSimpleBox;\n\n    var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH$1).getItemStyle();\n    setHoverStyle(el, hoverStyle);\n}\n\nfunction transInit$1(points, itemLayout) {\n    return map(points, function (point) {\n        point = point.slice();\n        point[1] = itemLayout.initBaseline;\n        return point;\n    });\n}\n\n\n\nvar LargeBoxPath = Path.extend({\n\n    type: 'largeCandlestickBox',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        for (var i = 0; i < points.length;) {\n            if (this.__sign === points[i++]) {\n                var x = points[i++];\n                ctx.moveTo(x, points[i++]);\n                ctx.lineTo(x, points[i++]);\n            }\n            else {\n                i += 3;\n            }\n        }\n    }\n});\n\nfunction createLarge$1(seriesModel, group, incremental) {\n    var data = seriesModel.getData();\n    var largePoints = data.getLayout('largePoints');\n\n    var elP = new LargeBoxPath({\n        shape: {points: largePoints},\n        __sign: 1\n    });\n    group.add(elP);\n    var elN = new LargeBoxPath({\n        shape: {points: largePoints},\n        __sign: -1\n    });\n    group.add(elN);\n\n    setLargeStyle$1(1, elP, seriesModel, data);\n    setLargeStyle$1(-1, elN, seriesModel, data);\n\n    if (incremental) {\n        elP.incremental = true;\n        elN.incremental = true;\n    }\n}\n\nfunction setLargeStyle$1(sign, el, seriesModel, data) {\n    var suffix = sign > 0 ? 'P' : 'N';\n    var borderColor = data.getVisual('borderColor' + suffix)\n        || data.getVisual('color' + suffix);\n\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var itemStyle = seriesModel.getModel(NORMAL_ITEM_STYLE_PATH$1).getItemStyle(SKIP_PROPS);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    // No different\n    // el.style.lineWidth = .5;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar preprocessor = function (option) {\n    if (!option || !isArray(option.series)) {\n        return;\n    }\n\n    // Translate 'k' to 'candlestick'.\n    each$1(option.series, function (seriesItem) {\n        if (isObject$1(seriesItem) && seriesItem.type === 'k') {\n            seriesItem.type = 'candlestick';\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar positiveBorderColorQuery = ['itemStyle', 'borderColor'];\nvar negativeBorderColorQuery = ['itemStyle', 'borderColor0'];\nvar positiveColorQuery = ['itemStyle', 'color'];\nvar negativeColorQuery = ['itemStyle', 'color0'];\n\nvar candlestickVisual = {\n\n    seriesType: 'candlestick',\n\n    plan: createRenderPlanner(),\n\n    // For legend.\n    performRawSeries: true,\n\n    reset: function (seriesModel, ecModel) {\n\n        var data = seriesModel.getData();\n        var isLargeRender = seriesModel.pipelineContext.large;\n\n        data.setVisual({\n            legendSymbol: 'roundRect',\n            colorP: getColor(1, seriesModel),\n            colorN: getColor(-1, seriesModel),\n            borderColorP: getBorderColor(1, seriesModel),\n            borderColorN: getBorderColor(-1, seriesModel)\n        });\n\n        // Only visible series has each data be visual encoded\n        if (ecModel.isSeriesFiltered(seriesModel)) {\n            return;\n        }\n\n        return !isLargeRender && {progress: progress};\n\n\n        function progress(params, data) {\n            var dataIndex;\n            while ((dataIndex = params.next()) != null) {\n                var itemModel = data.getItemModel(dataIndex);\n                var sign = data.getItemLayout(dataIndex).sign;\n\n                data.setItemVisual(\n                    dataIndex,\n                    {\n                        color: getColor(sign, itemModel),\n                        borderColor: getBorderColor(sign, itemModel)\n                    }\n                );\n            }\n        }\n\n        function getColor(sign, model) {\n            return model.get(\n                sign > 0 ? positiveColorQuery : negativeColorQuery\n            );\n        }\n\n        function getBorderColor(sign, model) {\n            return model.get(\n                sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery\n            );\n        }\n\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar LargeArr$1 = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nvar candlestickLayout = {\n\n    seriesType: 'candlestick',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n\n        var coordSys = seriesModel.coordinateSystem;\n        var data = seriesModel.getData();\n        var candleWidth = calculateCandleWidth(seriesModel, data);\n        var cDimIdx = 0;\n        var vDimIdx = 1;\n        var coordDims = ['x', 'y'];\n        var cDim = data.mapDimension(coordDims[cDimIdx]);\n        var vDims = data.mapDimension(coordDims[vDimIdx], true);\n        var openDim = vDims[0];\n        var closeDim = vDims[1];\n        var lowestDim = vDims[2];\n        var highestDim = vDims[3];\n\n        data.setLayout({\n            candleWidth: candleWidth,\n            // The value is experimented visually.\n            isSimpleBox: candleWidth <= 1.3\n        });\n\n        if (cDim == null || vDims.length < 4) {\n            return;\n        }\n\n        return {\n            progress: seriesModel.pipelineContext.large\n                ? largeProgress : normalProgress\n        };\n\n        function normalProgress(params, data) {\n            var dataIndex;\n            while ((dataIndex = params.next()) != null) {\n\n                var axisDimVal = data.get(cDim, dataIndex);\n                var openVal = data.get(openDim, dataIndex);\n                var closeVal = data.get(closeDim, dataIndex);\n                var lowestVal = data.get(lowestDim, dataIndex);\n                var highestVal = data.get(highestDim, dataIndex);\n\n                var ocLow = Math.min(openVal, closeVal);\n                var ocHigh = Math.max(openVal, closeVal);\n\n                var ocLowPoint = getPoint(ocLow, axisDimVal);\n                var ocHighPoint = getPoint(ocHigh, axisDimVal);\n                var lowestPoint = getPoint(lowestVal, axisDimVal);\n                var highestPoint = getPoint(highestVal, axisDimVal);\n\n                var ends = [];\n                addBodyEnd(ends, ocHighPoint, 0);\n                addBodyEnd(ends, ocLowPoint, 1);\n\n                ends.push(\n                    subPixelOptimizePoint(highestPoint),\n                    subPixelOptimizePoint(ocHighPoint),\n                    subPixelOptimizePoint(lowestPoint),\n                    subPixelOptimizePoint(ocLowPoint)\n                );\n\n                data.setItemLayout(dataIndex, {\n                    sign: getSign(data, dataIndex, openVal, closeVal, closeDim),\n                    initBaseline: openVal > closeVal\n                        ? ocHighPoint[vDimIdx] : ocLowPoint[vDimIdx], // open point.\n                    ends: ends,\n                    brushRect: makeBrushRect(lowestVal, highestVal, axisDimVal)\n                });\n            }\n\n            function getPoint(val, axisDimVal) {\n                var p = [];\n                p[cDimIdx] = axisDimVal;\n                p[vDimIdx] = val;\n                return (isNaN(axisDimVal) || isNaN(val))\n                    ? [NaN, NaN]\n                    : coordSys.dataToPoint(p);\n            }\n\n            function addBodyEnd(ends, point, start) {\n                var point1 = point.slice();\n                var point2 = point.slice();\n\n                point1[cDimIdx] = subPixelOptimize(\n                    point1[cDimIdx] + candleWidth / 2, 1, false\n                );\n                point2[cDimIdx] = subPixelOptimize(\n                    point2[cDimIdx] - candleWidth / 2, 1, true\n                );\n\n                start\n                    ? ends.push(point1, point2)\n                    : ends.push(point2, point1);\n            }\n\n            function makeBrushRect(lowestVal, highestVal, axisDimVal) {\n                var pmin = getPoint(lowestVal, axisDimVal);\n                var pmax = getPoint(highestVal, axisDimVal);\n\n                pmin[cDimIdx] -= candleWidth / 2;\n                pmax[cDimIdx] -= candleWidth / 2;\n\n                return {\n                    x: pmin[0],\n                    y: pmin[1],\n                    width: vDimIdx ? candleWidth : pmax[0] - pmin[0],\n                    height: vDimIdx ? pmax[1] - pmin[1] : candleWidth\n                };\n            }\n\n            function subPixelOptimizePoint(point) {\n                point[cDimIdx] = subPixelOptimize(point[cDimIdx], 1);\n                return point;\n            }\n        }\n\n        function largeProgress(params, data) {\n            // Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...]\n            var points = new LargeArr$1(params.count * 5);\n            var offset = 0;\n            var point;\n            var tmpIn = [];\n            var tmpOut = [];\n            var dataIndex;\n\n            while ((dataIndex = params.next()) != null) {\n                var axisDimVal = data.get(cDim, dataIndex);\n                var openVal = data.get(openDim, dataIndex);\n                var closeVal = data.get(closeDim, dataIndex);\n                var lowestVal = data.get(lowestDim, dataIndex);\n                var highestVal = data.get(highestDim, dataIndex);\n\n                if (isNaN(axisDimVal) || isNaN(lowestVal) || isNaN(highestVal)) {\n                    points[offset++] = NaN;\n                    offset += 4;\n                    continue;\n                }\n\n                points[offset++] = getSign(data, dataIndex, openVal, closeVal, closeDim);\n\n                tmpIn[cDimIdx] = axisDimVal;\n\n                tmpIn[vDimIdx] = lowestVal;\n                point = coordSys.dataToPoint(tmpIn, null, tmpOut);\n                points[offset++] = point ? point[0] : NaN;\n                points[offset++] = point ? point[1] : NaN;\n                tmpIn[vDimIdx] = highestVal;\n                point = coordSys.dataToPoint(tmpIn, null, tmpOut);\n                points[offset++] = point ? point[1] : NaN;\n            }\n\n            data.setLayout('largePoints', points);\n        }\n    }\n};\n\nfunction getSign(data, dataIndex, openVal, closeVal, closeDim) {\n    var sign;\n    if (openVal > closeVal) {\n        sign = -1;\n    }\n    else if (openVal < closeVal) {\n        sign = 1;\n    }\n    else {\n        sign = dataIndex > 0\n            // If close === open, compare with close of last record\n            ? (data.get(closeDim, dataIndex - 1) <= closeVal ? 1 : -1)\n            // No record of previous, set to be positive\n            : 1;\n    }\n\n    return sign;\n}\n\nfunction calculateCandleWidth(seriesModel, data) {\n    var baseAxis = seriesModel.getBaseAxis();\n    var extent;\n\n    var bandWidth = baseAxis.type === 'category'\n        ? baseAxis.getBandWidth()\n        : (\n            extent = baseAxis.getExtent(),\n            Math.abs(extent[1] - extent[0]) / data.count()\n        );\n\n    var barMaxWidth = parsePercent$1(\n        retrieve2(seriesModel.get('barMaxWidth'), bandWidth),\n        bandWidth\n    );\n    var barMinWidth = parsePercent$1(\n        retrieve2(seriesModel.get('barMinWidth'), 1),\n        bandWidth\n    );\n    var barWidth = seriesModel.get('barWidth');\n\n    return barWidth != null\n        ? parsePercent$1(barWidth, bandWidth)\n        // Put max outer to ensure bar visible in spite of overlap.\n        : Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(preprocessor);\nregisterVisual(candlestickVisual);\nregisterLayout(candlestickLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.effectScatter',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        effectType: 'ripple',\n\n        progressive: 0,\n\n        // When to show the effect, option: 'render'|'emphasis'\n        showEffectOn: 'render',\n\n        // Ripple effect config\n        rippleEffect: {\n            period: 4,\n            // Scale of ripple\n            scale: 2.5,\n            // Brush type can be fill or stroke\n            brushType: 'fill'\n        },\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        // large: false,\n        // Available when large is true\n        // largeThreshold: 2000,\n\n        // itemStyle: {\n        //     opacity: 1\n        // }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Symbol with ripple effect\n * @module echarts/chart/helper/EffectSymbol\n */\n\nvar EFFECT_RIPPLE_NUMBER = 3;\n\nfunction normalizeSymbolSize$1(symbolSize) {\n    if (!isArray(symbolSize)) {\n        symbolSize = [+symbolSize, +symbolSize];\n    }\n    return symbolSize;\n}\n\nfunction updateRipplePath(rippleGroup, effectCfg) {\n    rippleGroup.eachChild(function (ripplePath) {\n        ripplePath.attr({\n            z: effectCfg.z,\n            zlevel: effectCfg.zlevel,\n            style: {\n                stroke: effectCfg.brushType === 'stroke' ? effectCfg.color : null,\n                fill: effectCfg.brushType === 'fill' ? effectCfg.color : null\n            }\n        });\n    });\n}\n/**\n * @constructor\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction EffectSymbol(data, idx) {\n    Group.call(this);\n\n    var symbol = new SymbolClz$1(data, idx);\n    var rippleGroup = new Group();\n    this.add(symbol);\n    this.add(rippleGroup);\n\n    rippleGroup.beforeUpdate = function () {\n        this.attr(symbol.getScale());\n    };\n    this.updateData(data, idx);\n}\n\nvar effectSymbolProto = EffectSymbol.prototype;\n\neffectSymbolProto.stopEffectAnimation = function () {\n    this.childAt(1).removeAll();\n};\n\neffectSymbolProto.startEffectAnimation = function (effectCfg) {\n    var symbolType = effectCfg.symbolType;\n    var color = effectCfg.color;\n    var rippleGroup = this.childAt(1);\n\n    for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) {\n        // var ripplePath = createSymbol(\n        //     symbolType, -0.5, -0.5, 1, 1, color\n        // );\n        // If width/height are set too small (e.g., set to 1) on ios10\n        // and macOS Sierra, a circle stroke become a rect, no matter what\n        // the scale is set. So we set width/height as 2. See #4136.\n        var ripplePath = createSymbol(\n            symbolType, -1, -1, 2, 2, color\n        );\n        ripplePath.attr({\n            style: {\n                strokeNoScale: true\n            },\n            z2: 99,\n            silent: true,\n            scale: [0.5, 0.5]\n        });\n\n        var delay = -i / EFFECT_RIPPLE_NUMBER * effectCfg.period + effectCfg.effectOffset;\n        // TODO Configurable effectCfg.period\n        ripplePath.animate('', true)\n            .when(effectCfg.period, {\n                scale: [effectCfg.rippleScale / 2, effectCfg.rippleScale / 2]\n            })\n            .delay(delay)\n            .start();\n        ripplePath.animateStyle(true)\n            .when(effectCfg.period, {\n                opacity: 0\n            })\n            .delay(delay)\n            .start();\n\n        rippleGroup.add(ripplePath);\n    }\n\n    updateRipplePath(rippleGroup, effectCfg);\n};\n\n/**\n * Update effect symbol\n */\neffectSymbolProto.updateEffectAnimation = function (effectCfg) {\n    var oldEffectCfg = this._effectCfg;\n    var rippleGroup = this.childAt(1);\n\n    // Must reinitialize effect if following configuration changed\n    var DIFFICULT_PROPS = ['symbolType', 'period', 'rippleScale'];\n    for (var i = 0; i < DIFFICULT_PROPS.length; i++) {\n        var propName = DIFFICULT_PROPS[i];\n        if (oldEffectCfg[propName] !== effectCfg[propName]) {\n            this.stopEffectAnimation();\n            this.startEffectAnimation(effectCfg);\n            return;\n        }\n    }\n\n    updateRipplePath(rippleGroup, effectCfg);\n};\n\n/**\n * Highlight symbol\n */\neffectSymbolProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\neffectSymbolProto.downplay = function () {\n    this.trigger('normal');\n};\n\n/**\n * Update symbol properties\n * @param  {module:echarts/data/List} data\n * @param  {number} idx\n */\neffectSymbolProto.updateData = function (data, idx) {\n    var seriesModel = data.hostModel;\n\n    this.childAt(0).updateData(data, idx);\n\n    var rippleGroup = this.childAt(1);\n    var itemModel = data.getItemModel(idx);\n    var symbolType = data.getItemVisual(idx, 'symbol');\n    var symbolSize = normalizeSymbolSize$1(data.getItemVisual(idx, 'symbolSize'));\n    var color = data.getItemVisual(idx, 'color');\n\n    rippleGroup.attr('scale', symbolSize);\n\n    rippleGroup.traverse(function (ripplePath) {\n        ripplePath.attr({\n            fill: color\n        });\n    });\n\n    var symbolOffset = itemModel.getShallow('symbolOffset');\n    if (symbolOffset) {\n        var pos = rippleGroup.position;\n        pos[0] = parsePercent$1(symbolOffset[0], symbolSize[0]);\n        pos[1] = parsePercent$1(symbolOffset[1], symbolSize[1]);\n    }\n    rippleGroup.rotation = (itemModel.getShallow('symbolRotate') || 0) * Math.PI / 180 || 0;\n\n    var effectCfg = {};\n\n    effectCfg.showEffectOn = seriesModel.get('showEffectOn');\n    effectCfg.rippleScale = itemModel.get('rippleEffect.scale');\n    effectCfg.brushType = itemModel.get('rippleEffect.brushType');\n    effectCfg.period = itemModel.get('rippleEffect.period') * 1000;\n    effectCfg.effectOffset = idx / data.count();\n    effectCfg.z = itemModel.getShallow('z') || 0;\n    effectCfg.zlevel = itemModel.getShallow('zlevel') || 0;\n    effectCfg.symbolType = symbolType;\n    effectCfg.color = color;\n\n    this.off('mouseover').off('mouseout').off('emphasis').off('normal');\n\n    if (effectCfg.showEffectOn === 'render') {\n        this._effectCfg\n            ? this.updateEffectAnimation(effectCfg)\n            : this.startEffectAnimation(effectCfg);\n\n        this._effectCfg = effectCfg;\n    }\n    else {\n        // Not keep old effect config\n        this._effectCfg = null;\n\n        this.stopEffectAnimation();\n        var symbol = this.childAt(0);\n        var onEmphasis = function () {\n            symbol.highlight();\n            if (effectCfg.showEffectOn !== 'render') {\n                this.startEffectAnimation(effectCfg);\n            }\n        };\n        var onNormal = function () {\n            symbol.downplay();\n            if (effectCfg.showEffectOn !== 'render') {\n                this.stopEffectAnimation();\n            }\n        };\n        this.on('mouseover', onEmphasis, this)\n            .on('mouseout', onNormal, this)\n            .on('emphasis', onEmphasis, this)\n            .on('normal', onNormal, this);\n    }\n\n    this._effectCfg = effectCfg;\n};\n\neffectSymbolProto.fadeOut = function (cb) {\n    this.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    cb && cb();\n};\n\ninherits(EffectSymbol, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'effectScatter',\n\n    init: function () {\n        this._symbolDraw = new SymbolDraw(EffectSymbol);\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var effectSymbolDraw = this._symbolDraw;\n        effectSymbolDraw.updateData(data);\n        this.group.add(effectSymbolDraw.group);\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        this.group.dirty();\n\n        var res = pointsLayout().reset(seriesModel);\n        if (res.progress) {\n            res.progress({ start: 0, end: data.count() }, data);\n        }\n\n        this._symbolDraw.updateLayout(data);\n    },\n\n    _updateGroupTransform: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.getRoamTransform) {\n            this.group.transform = clone$2(coordSys.getRoamTransform());\n            this.group.decomposeTransform();\n        }\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(api);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(visualSymbol('effectScatter', 'circle'));\nregisterLayout(pointsLayout('effectScatter'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint32Array, Float64Array, Float32Array */\n\nvar Uint32Arr = typeof Uint32Array === 'undefined' ? Array : Uint32Array;\nvar Float64Arr = typeof Float64Array === 'undefined' ? Array : Float64Array;\n\nfunction compatEc2(seriesOpt) {\n    var data = seriesOpt.data;\n    if (data && data[0] && data[0][0] && data[0][0].coord) {\n        if (__DEV__) {\n            console.warn('Lines data configuration has been changed to'\n                + ' { coords:[[1,2],[2,3]] }');\n        }\n        seriesOpt.data = map(data, function (itemOpt) {\n            var coords = [\n                itemOpt[0].coord, itemOpt[1].coord\n            ];\n            var target = {\n                coords: coords\n            };\n            if (itemOpt[0].name) {\n                target.fromName = itemOpt[0].name;\n            }\n            if (itemOpt[1].name) {\n                target.toName = itemOpt[1].name;\n            }\n            return mergeAll([target, itemOpt[0], itemOpt[1]]);\n        });\n    }\n}\n\nvar LinesSeries = SeriesModel.extend({\n\n    type: 'series.lines',\n\n    dependencies: ['grid', 'polar'],\n\n    visualColorAccessPath: 'lineStyle.color',\n\n    init: function (option) {\n        // The input data may be null/undefined.\n        option.data = option.data || [];\n\n        // Not using preprocessor because mergeOption may not have series.type\n        compatEc2(option);\n\n        var result = this._processFlatCoordsArray(option.data);\n        this._flatCoords = result.flatCoords;\n        this._flatCoordsOffset = result.flatCoordsOffset;\n        if (result.flatCoords) {\n            option.data = new Float32Array(result.count);\n        }\n\n        LinesSeries.superApply(this, 'init', arguments);\n    },\n\n    mergeOption: function (option) {\n        // The input data may be null/undefined.\n        option.data = option.data || [];\n\n        compatEc2(option);\n\n        if (option.data) {\n            // Only update when have option data to merge.\n            var result = this._processFlatCoordsArray(option.data);\n            this._flatCoords = result.flatCoords;\n            this._flatCoordsOffset = result.flatCoordsOffset;\n            if (result.flatCoords) {\n                option.data = new Float32Array(result.count);\n            }\n        }\n\n        LinesSeries.superApply(this, 'mergeOption', arguments);\n    },\n\n    appendData: function (params) {\n        var result = this._processFlatCoordsArray(params.data);\n        if (result.flatCoords) {\n            if (!this._flatCoords) {\n                this._flatCoords = result.flatCoords;\n                this._flatCoordsOffset = result.flatCoordsOffset;\n            }\n            else {\n                this._flatCoords = concatArray(this._flatCoords, result.flatCoords);\n                this._flatCoordsOffset = concatArray(this._flatCoordsOffset, result.flatCoordsOffset);\n            }\n            params.data = new Float32Array(result.count);\n        }\n\n        this.getRawData().appendData(params.data);\n    },\n\n    _getCoordsFromItemModel: function (idx) {\n        var itemModel = this.getData().getItemModel(idx);\n        var coords = (itemModel.option instanceof Array)\n            ? itemModel.option : itemModel.getShallow('coords');\n\n        if (__DEV__) {\n            if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) {\n                throw new Error(\n                    'Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.'\n                );\n            }\n        }\n        return coords;\n    },\n\n    getLineCoordsCount: function (idx) {\n        if (this._flatCoordsOffset) {\n            return this._flatCoordsOffset[idx * 2 + 1];\n        }\n        else {\n            return this._getCoordsFromItemModel(idx).length;\n        }\n    },\n\n    getLineCoords: function (idx, out) {\n        if (this._flatCoordsOffset) {\n            var offset = this._flatCoordsOffset[idx * 2];\n            var len = this._flatCoordsOffset[idx * 2 + 1];\n            for (var i = 0; i < len; i++) {\n                out[i] = out[i] || [];\n                out[i][0] = this._flatCoords[offset + i * 2];\n                out[i][1] = this._flatCoords[offset + i * 2 + 1];\n            }\n            return len;\n        }\n        else {\n            var coords = this._getCoordsFromItemModel(idx);\n            for (var i = 0; i < coords.length; i++) {\n                out[i] = out[i] || [];\n                out[i][0] = coords[i][0];\n                out[i][1] = coords[i][1];\n            }\n            return coords.length;\n        }\n    },\n\n    _processFlatCoordsArray: function (data) {\n        var startOffset = 0;\n        if (this._flatCoords) {\n            startOffset = this._flatCoords.length;\n        }\n        // Stored as a typed array. In format\n        // Points Count(2) | x | y | x | y | Points Count(3) | x |  y | x | y | x | y |\n        if (typeof data[0] === 'number') {\n            var len = data.length;\n            // Store offset and len of each segment\n            var coordsOffsetAndLenStorage = new Uint32Arr(len);\n            var coordsStorage = new Float64Arr(len);\n            var coordsCursor = 0;\n            var offsetCursor = 0;\n            var dataCount = 0;\n            for (var i = 0; i < len;) {\n                dataCount++;\n                var count = data[i++];\n                // Offset\n                coordsOffsetAndLenStorage[offsetCursor++] = coordsCursor + startOffset;\n                // Len\n                coordsOffsetAndLenStorage[offsetCursor++] = count;\n                for (var k = 0; k < count; k++) {\n                    var x = data[i++];\n                    var y = data[i++];\n                    coordsStorage[coordsCursor++] = x;\n                    coordsStorage[coordsCursor++] = y;\n\n                    if (i > len) {\n                        if (__DEV__) {\n                            throw new Error('Invalid data format.');\n                        }\n                    }\n                }\n            }\n\n            return {\n                flatCoordsOffset: new Uint32Array(coordsOffsetAndLenStorage.buffer, 0, offsetCursor),\n                flatCoords: coordsStorage,\n                count: dataCount\n            };\n        }\n\n        return {\n            flatCoordsOffset: null,\n            flatCoords: null,\n            count: data.length\n        };\n    },\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var CoordSys = CoordinateSystemManager.get(option.coordinateSystem);\n            if (!CoordSys) {\n                throw new Error('Unkown coordinate system ' + option.coordinateSystem);\n            }\n        }\n\n        var lineData = new List(['value'], this);\n        lineData.hasItemOption = false;\n\n        lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) {\n            // dataItem is simply coords\n            if (dataItem instanceof Array) {\n                return NaN;\n            }\n            else {\n                lineData.hasItemOption = true;\n                var value = dataItem.value;\n                if (value != null) {\n                    return value instanceof Array ? value[dimIndex] : value;\n                }\n            }\n        });\n\n        return lineData;\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var itemModel = data.getItemModel(dataIndex);\n        var name = itemModel.get('name');\n        if (name) {\n            return name;\n        }\n        var fromName = itemModel.get('fromName');\n        var toName = itemModel.get('toName');\n        var html = [];\n        fromName != null && html.push(fromName);\n        toName != null && html.push(toName);\n\n        return encodeHTML(html.join(' > '));\n    },\n\n    preventIncremental: function () {\n        return !!this.get('effect.show');\n    },\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            return this.option.large ? 1e4 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            return this.option.large ? 2e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'geo',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        xAxisIndex: 0,\n        yAxisIndex: 0,\n\n        symbol: ['none', 'none'],\n        symbolSize: [10, 10],\n        // Geo coordinate system\n        geoIndex: 0,\n\n        effect: {\n            show: false,\n            period: 4,\n            // Animation delay. support callback\n            // delay: 0,\n            // If move with constant speed px/sec\n            // period will be ignored if this property is > 0,\n            constantSpeed: 0,\n            symbol: 'circle',\n            symbolSize: 3,\n            loop: true,\n            // Length of trail, 0 - 1\n            trailLength: 0.2\n            // Same with lineStyle.color\n            // color\n        },\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n\n        // If lines are polyline\n        // polyline not support curveness, label, animation\n        polyline: false,\n\n        label: {\n            show: false,\n            position: 'end'\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n        },\n\n        lineStyle: {\n            opacity: 0.5\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Provide effect for line\n * @module echarts/chart/helper/EffectLine\n */\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction EffectLine(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this.add(this.createLine(lineData, idx, seriesScope));\n\n    this._updateEffectSymbol(lineData, idx);\n}\n\nvar effectLineProto = EffectLine.prototype;\n\neffectLineProto.createLine = function (lineData, idx, seriesScope) {\n    return new Line$1(lineData, idx, seriesScope);\n};\n\neffectLineProto._updateEffectSymbol = function (lineData, idx) {\n    var itemModel = lineData.getItemModel(idx);\n    var effectModel = itemModel.getModel('effect');\n    var size = effectModel.get('symbolSize');\n    var symbolType = effectModel.get('symbol');\n    if (!isArray(size)) {\n        size = [size, size];\n    }\n    var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color');\n    var symbol = this.childAt(1);\n\n    if (this._symbolType !== symbolType) {\n        // Remove previous\n        this.remove(symbol);\n\n        symbol = createSymbol(\n            symbolType, -0.5, -0.5, 1, 1, color\n        );\n        symbol.z2 = 100;\n        symbol.culling = true;\n\n        this.add(symbol);\n    }\n\n    // Symbol may be removed if loop is false\n    if (!symbol) {\n        return;\n    }\n\n    // Shadow color is same with color in default\n    symbol.setStyle('shadowColor', color);\n    symbol.setStyle(effectModel.getItemStyle(['color']));\n\n    symbol.attr('scale', size);\n\n    symbol.setColor(color);\n    symbol.attr('scale', size);\n\n    this._symbolType = symbolType;\n\n    this._updateEffectAnimation(lineData, effectModel, idx);\n};\n\neffectLineProto._updateEffectAnimation = function (lineData, effectModel, idx) {\n\n    var symbol = this.childAt(1);\n    if (!symbol) {\n        return;\n    }\n\n    var self = this;\n\n    var points = lineData.getItemLayout(idx);\n\n    var period = effectModel.get('period') * 1000;\n    var loop = effectModel.get('loop');\n    var constantSpeed = effectModel.get('constantSpeed');\n    var delayExpr = retrieve(effectModel.get('delay'), function (idx) {\n        return idx / lineData.count() * period / 3;\n    });\n    var isDelayFunc = typeof delayExpr === 'function';\n\n    // Ignore when updating\n    symbol.ignore = true;\n\n    this.updateAnimationPoints(symbol, points);\n\n    if (constantSpeed > 0) {\n        period = this.getLineLength(symbol) / constantSpeed * 1000;\n    }\n\n    if (period !== this._period || loop !== this._loop) {\n\n        symbol.stopAnimation();\n\n        var delay = delayExpr;\n        if (isDelayFunc) {\n            delay = delayExpr(idx);\n        }\n        if (symbol.__t > 0) {\n            delay = -period * symbol.__t;\n        }\n        symbol.__t = 0;\n        var animator = symbol.animate('', loop)\n            .when(period, {\n                __t: 1\n            })\n            .delay(delay)\n            .during(function () {\n                self.updateSymbolPosition(symbol);\n            });\n        if (!loop) {\n            animator.done(function () {\n                self.remove(symbol);\n            });\n        }\n        animator.start();\n    }\n\n    this._period = period;\n    this._loop = loop;\n};\n\neffectLineProto.getLineLength = function (symbol) {\n    // Not so accurate\n    return (dist(symbol.__p1, symbol.__cp1)\n        + dist(symbol.__cp1, symbol.__p2));\n};\n\neffectLineProto.updateAnimationPoints = function (symbol, points) {\n    symbol.__p1 = points[0];\n    symbol.__p2 = points[1];\n    symbol.__cp1 = points[2] || [\n        (points[0][0] + points[1][0]) / 2,\n        (points[0][1] + points[1][1]) / 2\n    ];\n};\n\neffectLineProto.updateData = function (lineData, idx, seriesScope) {\n    this.childAt(0).updateData(lineData, idx, seriesScope);\n    this._updateEffectSymbol(lineData, idx);\n};\n\neffectLineProto.updateSymbolPosition = function (symbol) {\n    var p1 = symbol.__p1;\n    var p2 = symbol.__p2;\n    var cp1 = symbol.__cp1;\n    var t = symbol.__t;\n    var pos = symbol.position;\n    var quadraticAt$$1 = quadraticAt;\n    var quadraticDerivativeAt$$1 = quadraticDerivativeAt;\n    pos[0] = quadraticAt$$1(p1[0], cp1[0], p2[0], t);\n    pos[1] = quadraticAt$$1(p1[1], cp1[1], p2[1], t);\n\n    // Tangent\n    var tx = quadraticDerivativeAt$$1(p1[0], cp1[0], p2[0], t);\n    var ty = quadraticDerivativeAt$$1(p1[1], cp1[1], p2[1], t);\n\n    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;\n\n    symbol.ignore = false;\n};\n\n\neffectLineProto.updateLayout = function (lineData, idx) {\n    this.childAt(0).updateLayout(lineData, idx);\n\n    var effectModel = lineData.getItemModel(idx).getModel('effect');\n    this._updateEffectAnimation(lineData, effectModel, idx);\n};\n\ninherits(EffectLine, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Polyline}\n */\nfunction Polyline$2(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createPolyline(lineData, idx, seriesScope);\n}\n\nvar polylineProto = Polyline$2.prototype;\n\npolylineProto._createPolyline = function (lineData, idx, seriesScope) {\n    // var seriesModel = lineData.hostModel;\n    var points = lineData.getItemLayout(idx);\n\n    var line = new Polyline({\n        shape: {\n            points: points\n        }\n    });\n\n    this.add(line);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\npolylineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childAt(0);\n    var target = {\n        shape: {\n            points: lineData.getItemLayout(idx)\n        }\n    };\n    updateProps(line, target, seriesModel, idx);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\npolylineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var line = this.childAt(0);\n    var itemModel = lineData.getItemModel(idx);\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n\n    if (!seriesScope || lineData.hasItemOption) {\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n    }\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    setHoverStyle(this);\n};\n\npolylineProto.updateLayout = function (lineData, idx) {\n    var polyline = this.childAt(0);\n    polyline.setShape('points', lineData.getItemLayout(idx));\n};\n\ninherits(Polyline$2, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Provide effect for line\n * @module echarts/chart/helper/EffectLine\n */\n\n/**\n * @constructor\n * @extends {module:echarts/chart/helper/EffectLine}\n * @alias {module:echarts/chart/helper/Polyline}\n */\nfunction EffectPolyline(lineData, idx, seriesScope) {\n    EffectLine.call(this, lineData, idx, seriesScope);\n    this._lastFrame = 0;\n    this._lastFramePercent = 0;\n}\n\nvar effectPolylineProto = EffectPolyline.prototype;\n\n// Overwrite\neffectPolylineProto.createLine = function (lineData, idx, seriesScope) {\n    return new Polyline$2(lineData, idx, seriesScope);\n};\n\n// Overwrite\neffectPolylineProto.updateAnimationPoints = function (symbol, points) {\n    this._points = points;\n    var accLenArr = [0];\n    var len$$1 = 0;\n    for (var i = 1; i < points.length; i++) {\n        var p1 = points[i - 1];\n        var p2 = points[i];\n        len$$1 += dist(p1, p2);\n        accLenArr.push(len$$1);\n    }\n    if (len$$1 === 0) {\n        return;\n    }\n\n    for (var i = 0; i < accLenArr.length; i++) {\n        accLenArr[i] /= len$$1;\n    }\n    this._offsets = accLenArr;\n    this._length = len$$1;\n};\n\n// Overwrite\neffectPolylineProto.getLineLength = function (symbol) {\n    return this._length;\n};\n\n// Overwrite\neffectPolylineProto.updateSymbolPosition = function (symbol) {\n    var t = symbol.__t;\n    var points = this._points;\n    var offsets = this._offsets;\n    var len$$1 = points.length;\n\n    if (!offsets) {\n        // Has length 0\n        return;\n    }\n\n    var lastFrame = this._lastFrame;\n    var frame;\n\n    if (t < this._lastFramePercent) {\n        // Start from the next frame\n        // PENDING start from lastFrame ?\n        var start = Math.min(lastFrame + 1, len$$1 - 1);\n        for (frame = start; frame >= 0; frame--) {\n            if (offsets[frame] <= t) {\n                break;\n            }\n        }\n        // PENDING really need to do this ?\n        frame = Math.min(frame, len$$1 - 2);\n    }\n    else {\n        for (var frame = lastFrame; frame < len$$1; frame++) {\n            if (offsets[frame] > t) {\n                break;\n            }\n        }\n        frame = Math.min(frame - 1, len$$1 - 2);\n    }\n\n    lerp(\n        symbol.position, points[frame], points[frame + 1],\n        (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame])\n    );\n\n    var tx = points[frame + 1][0] - points[frame][0];\n    var ty = points[frame + 1][1] - points[frame][1];\n    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;\n\n    this._lastFrame = frame;\n    this._lastFramePercent = t;\n\n    symbol.ignore = false;\n};\n\ninherits(EffectPolyline, EffectLine);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Batch by color\n\nvar LargeLineShape = extendShape({\n\n    shape: {\n        polyline: false,\n        curveness: 0,\n        segs: []\n    },\n\n    buildPath: function (path, shape) {\n        var segs = shape.segs;\n        var curveness = shape.curveness;\n\n        if (shape.polyline) {\n            for (var i = 0; i < segs.length;) {\n                var count = segs[i++];\n                if (count > 0) {\n                    path.moveTo(segs[i++], segs[i++]);\n                    for (var k = 1; k < count; k++) {\n                        path.lineTo(segs[i++], segs[i++]);\n                    }\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < segs.length;) {\n                var x0 = segs[i++];\n                var y0 = segs[i++];\n                var x1 = segs[i++];\n                var y1 = segs[i++];\n                path.moveTo(x0, y0);\n                if (curveness > 0) {\n                    var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;\n                    var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;\n                    path.quadraticCurveTo(x2, y2, x1, y1);\n                }\n                else {\n                    path.lineTo(x1, y1);\n                }\n            }\n        }\n    },\n\n    findDataIndex: function (x, y) {\n\n        var shape = this.shape;\n        var segs = shape.segs;\n        var curveness = shape.curveness;\n\n        if (shape.polyline) {\n            var dataIndex = 0;\n            for (var i = 0; i < segs.length;) {\n                var count = segs[i++];\n                if (count > 0) {\n                    var x0 = segs[i++];\n                    var y0 = segs[i++];\n                    for (var k = 1; k < count; k++) {\n                        var x1 = segs[i++];\n                        var y1 = segs[i++];\n                        if (containStroke$1(x0, y0, x1, y1)) {\n                            return dataIndex;\n                        }\n                    }\n                }\n\n                dataIndex++;\n            }\n        }\n        else {\n            var dataIndex = 0;\n            for (var i = 0; i < segs.length;) {\n                var x0 = segs[i++];\n                var y0 = segs[i++];\n                var x1 = segs[i++];\n                var y1 = segs[i++];\n                if (curveness > 0) {\n                    var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;\n                    var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;\n\n                    if (containStroke$3(x0, y0, x2, y2, x1, y1)) {\n                        return dataIndex;\n                    }\n                }\n                else {\n                    if (containStroke$1(x0, y0, x1, y1)) {\n                        return dataIndex;\n                    }\n                }\n\n                dataIndex++;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeLineDraw() {\n    this.group = new Group();\n}\n\nvar largeLineProto = LargeLineDraw.prototype;\n\nlargeLineProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeLineProto.updateData = function (data) {\n    this.group.removeAll();\n\n    var lineEl = new LargeLineShape({\n        rectHover: true,\n        cursor: 'default'\n    });\n    lineEl.setShape({\n        segs: data.getLayout('linesPoints')\n    });\n\n    this._setCommon(lineEl, data);\n\n    // Add back\n    this.group.add(lineEl);\n\n    this._incremental = null;\n};\n\n/**\n * @override\n */\nlargeLineProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n\n    if (data.count() > 5e5) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\n/**\n * @override\n */\nlargeLineProto.incrementalUpdate = function (taskParams, data) {\n    var lineEl = new LargeLineShape();\n    lineEl.setShape({\n        segs: data.getLayout('linesPoints')\n    });\n\n    this._setCommon(lineEl, data, !!this._incremental);\n\n    if (!this._incremental) {\n        lineEl.rectHover = true;\n        lineEl.cursor = 'default';\n        lineEl.__startIndex = taskParams.start;\n        this.group.add(lineEl);\n    }\n    else {\n        this._incremental.addDisplayable(lineEl, true);\n    }\n};\n\n/**\n * @override\n */\nlargeLineProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeLineProto._setCommon = function (lineEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    lineEl.setShape({\n        polyline: hostModel.get('polyline'),\n        curveness: hostModel.get('lineStyle.curveness')\n    });\n\n    lineEl.useStyle(\n        hostModel.getModel('lineStyle').getLineStyle()\n    );\n    lineEl.style.strokeNoScale = true;\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        lineEl.setStyle('stroke', visualColor);\n    }\n    lineEl.setStyle('fill');\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        lineEl.seriesIndex = hostModel.seriesIndex;\n        lineEl.on('mousemove', function (e) {\n            lineEl.dataIndex = null;\n            var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex > 0) {\n                // Provide dataIndex for tooltip\n                lineEl.dataIndex = dataIndex + lineEl.__startIndex;\n            }\n        });\n    }\n};\n\nlargeLineProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar linesLayout = {\n    seriesType: 'lines',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        var isPolyline = seriesModel.get('polyline');\n        var isLarge = seriesModel.pipelineContext.large;\n\n        function progress(params, lineData) {\n            var lineCoords = [];\n            if (isLarge) {\n                var points;\n                var segCount = params.end - params.start;\n                if (isPolyline) {\n                    var totalCoordsCount = 0;\n                    for (var i = params.start; i < params.end; i++) {\n                        totalCoordsCount += seriesModel.getLineCoordsCount(i);\n                    }\n                    points = new Float32Array(segCount + totalCoordsCount * 2);\n                }\n                else {\n                    points = new Float32Array(segCount * 4);\n                }\n\n                var offset = 0;\n                var pt = [];\n                for (var i = params.start; i < params.end; i++) {\n                    var len = seriesModel.getLineCoords(i, lineCoords);\n                    if (isPolyline) {\n                        points[offset++] = len;\n                    }\n                    for (var k = 0; k < len; k++) {\n                        pt = coordSys.dataToPoint(lineCoords[k], false, pt);\n                        points[offset++] = pt[0];\n                        points[offset++] = pt[1];\n                    }\n                }\n\n                lineData.setLayout('linesPoints', points);\n            }\n            else {\n                for (var i = params.start; i < params.end; i++) {\n                    var itemModel = lineData.getItemModel(i);\n                    var len = seriesModel.getLineCoords(i, lineCoords);\n\n                    var pts = [];\n                    if (isPolyline) {\n                        for (var j = 0; j < len; j++) {\n                            pts.push(coordSys.dataToPoint(lineCoords[j]));\n                        }\n                    }\n                    else {\n                        pts[0] = coordSys.dataToPoint(lineCoords[0]);\n                        pts[1] = coordSys.dataToPoint(lineCoords[1]);\n\n                        var curveness = itemModel.get('lineStyle.curveness');\n                        if (+curveness) {\n                            pts[2] = [\n                                (pts[0][0] + pts[1][0]) / 2 - (pts[0][1] - pts[1][1]) * curveness,\n                                (pts[0][1] + pts[1][1]) / 2 - (pts[1][0] - pts[0][0]) * curveness\n                            ];\n                        }\n                    }\n                    lineData.setItemLayout(i, pts);\n                }\n            }\n        }\n\n        return { progress: progress };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'lines',\n\n    init: function () {},\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var lineDraw = this._updateLineDraw(data, seriesModel);\n\n        var zlevel = seriesModel.get('zlevel');\n        var trailLength = seriesModel.get('effect.trailLength');\n\n        var zr = api.getZr();\n        // Avoid the drag cause ghost shadow\n        // FIXME Better way ?\n        // SVG doesn't support\n        var isSvg = zr.painter.getType() === 'svg';\n        if (!isSvg) {\n            zr.painter.getLayer(zlevel).clear(true);\n        }\n        // Config layer with motion blur\n        if (this._lastZlevel != null && !isSvg) {\n            zr.configLayer(this._lastZlevel, {\n                motionBlur: false\n            });\n        }\n        if (this._showEffect(seriesModel) && trailLength) {\n            if (__DEV__) {\n                var notInIndividual = false;\n                ecModel.eachSeries(function (otherSeriesModel) {\n                    if (otherSeriesModel !== seriesModel && otherSeriesModel.get('zlevel') === zlevel) {\n                        notInIndividual = true;\n                    }\n                });\n                notInIndividual && console.warn('Lines with trail effect should have an individual zlevel');\n            }\n\n            if (!isSvg) {\n                zr.configLayer(zlevel, {\n                    motionBlur: true,\n                    lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0)\n                });\n            }\n        }\n\n        lineDraw.updateData(data);\n\n        this._lastZlevel = zlevel;\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var lineDraw = this._updateLineDraw(data, seriesModel);\n\n        lineDraw.incrementalPrepareUpdate(data);\n\n        this._clearLayer(api);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var pipelineContext = seriesModel.pipelineContext;\n\n        if (!this._finished || pipelineContext.large || pipelineContext.progressiveRender) {\n            // TODO Don't have to do update in large mode. Only do it when there are millions of data.\n            return {\n                update: true\n            };\n        }\n        else {\n            // TODO Use same logic with ScatterView.\n            // Manually update layout\n            var res = linesLayout.reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n            this._lineDraw.updateLayout();\n            this._clearLayer(api);\n        }\n    },\n\n    _updateLineDraw: function (data, seriesModel) {\n        var lineDraw = this._lineDraw;\n        var hasEffect = this._showEffect(seriesModel);\n        var isPolyline = !!seriesModel.get('polyline');\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (__DEV__) {\n            if (hasEffect && isLargeDraw) {\n                console.warn('Large lines not support effect');\n            }\n        }\n        if (!lineDraw\n            || hasEffect !== this._hasEffet\n            || isPolyline !== this._isPolyline\n            || isLargeDraw !== this._isLargeDraw\n        ) {\n            if (lineDraw) {\n                lineDraw.remove();\n            }\n            lineDraw = this._lineDraw = isLargeDraw\n                ? new LargeLineDraw()\n                : new LineDraw(\n                    isPolyline\n                        ? (hasEffect ? EffectPolyline : Polyline$2)\n                        : (hasEffect ? EffectLine : Line$1)\n                );\n            this._hasEffet = hasEffect;\n            this._isPolyline = isPolyline;\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(lineDraw.group);\n\n        return lineDraw;\n    },\n\n    _showEffect: function (seriesModel) {\n        return !!seriesModel.get('effect.show');\n    },\n\n    _clearLayer: function (api) {\n        // Not use motion when dragging or zooming\n        var zr = api.getZr();\n        var isSvg = zr.painter.getType() === 'svg';\n        if (!isSvg && this._lastZlevel != null) {\n            zr.painter.getLayer(this._lastZlevel).clear(true);\n        }\n    },\n\n    remove: function (ecModel, api) {\n        this._lineDraw && this._lineDraw.remove();\n        this._lineDraw = null;\n        // Clear motion when lineDraw is removed\n        this._clearLayer(api);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction normalize$2(a) {\n    if (!(a instanceof Array)) {\n        a = [a, a];\n    }\n    return a;\n}\n\nvar opacityQuery = 'lineStyle.opacity'.split('.');\n\nvar linesVisual = {\n    seriesType: 'lines',\n    reset: function (seriesModel, ecModel, api) {\n        var symbolType = normalize$2(seriesModel.get('symbol'));\n        var symbolSize = normalize$2(seriesModel.get('symbolSize'));\n        var data = seriesModel.getData();\n\n        data.setVisual('fromSymbol', symbolType && symbolType[0]);\n        data.setVisual('toSymbol', symbolType && symbolType[1]);\n        data.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);\n        data.setVisual('toSymbolSize', symbolSize && symbolSize[1]);\n        data.setVisual('opacity', seriesModel.get(opacityQuery));\n\n        function dataEach(data, idx) {\n            var itemModel = data.getItemModel(idx);\n            var symbolType = normalize$2(itemModel.getShallow('symbol', true));\n            var symbolSize = normalize$2(itemModel.getShallow('symbolSize', true));\n            var opacity = itemModel.get(opacityQuery);\n\n            symbolType[0] && data.setItemVisual(idx, 'fromSymbol', symbolType[0]);\n            symbolType[1] && data.setItemVisual(idx, 'toSymbol', symbolType[1]);\n            symbolSize[0] && data.setItemVisual(idx, 'fromSymbolSize', symbolSize[0]);\n            symbolSize[1] && data.setItemVisual(idx, 'toSymbolSize', symbolSize[1]);\n\n            data.setItemVisual(idx, 'opacity', opacity);\n        }\n\n        return {dataEach: data.hasItemOption ? dataEach : null};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(linesLayout);\nregisterVisual(linesVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n    type: 'series.heatmap',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this, {\n            generateCoord: 'value'\n        });\n    },\n\n    preventIncremental: function () {\n        var coordSysCreator = CoordinateSystemManager.get(this.get('coordinateSystem'));\n        if (coordSysCreator && coordSysCreator.dimensions) {\n            return coordSysCreator.dimensions[0] === 'lng' && coordSysCreator.dimensions[1] === 'lat';\n        }\n    },\n\n    defaultOption: {\n\n        // Cartesian2D or geo\n        coordinateSystem: 'cartesian2d',\n\n        zlevel: 0,\n\n        z: 2,\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Geo coordinate system\n        geoIndex: 0,\n\n        blurSize: 30,\n\n        pointSize: 20,\n\n        maxOpacity: 1,\n\n        minOpacity: 0\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8ClampedArray */\n\n/**\n * @file defines echarts Heatmap Chart\n * @author Ovilia (me@zhangwenli.com)\n * Inspired by https://github.com/mourner/simpleheat\n *\n * @module\n */\n\nvar GRADIENT_LEVELS = 256;\n\n/**\n * Heatmap Chart\n *\n * @class\n */\nfunction Heatmap() {\n    var canvas = createCanvas();\n    this.canvas = canvas;\n\n    this.blurSize = 30;\n    this.pointSize = 20;\n\n    this.maxOpacity = 1;\n    this.minOpacity = 0;\n\n    this._gradientPixels = {};\n}\n\nHeatmap.prototype = {\n    /**\n     * Renders Heatmap and returns the rendered canvas\n     * @param {Array} data array of data, each has x, y, value\n     * @param {number} width canvas width\n     * @param {number} height canvas height\n     */\n    update: function (data, width, height, normalize, colorFunc, isInRange) {\n        var brush = this._getBrush();\n        var gradientInRange = this._getGradient(data, colorFunc, 'inRange');\n        var gradientOutOfRange = this._getGradient(data, colorFunc, 'outOfRange');\n        var r = this.pointSize + this.blurSize;\n\n        var canvas = this.canvas;\n        var ctx = canvas.getContext('2d');\n        var len = data.length;\n        canvas.width = width;\n        canvas.height = height;\n        for (var i = 0; i < len; ++i) {\n            var p = data[i];\n            var x = p[0];\n            var y = p[1];\n            var value = p[2];\n\n            // calculate alpha using value\n            var alpha = normalize(value);\n\n            // draw with the circle brush with alpha\n            ctx.globalAlpha = alpha;\n            ctx.drawImage(brush, x - r, y - r);\n        }\n\n        if (!canvas.width || !canvas.height) {\n            // Avoid \"Uncaught DOMException: Failed to execute 'getImageData' on\n            // 'CanvasRenderingContext2D': The source height is 0.\"\n            return canvas;\n        }\n\n        // colorize the canvas using alpha value and set with gradient\n        var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n        var pixels = imageData.data;\n        var offset = 0;\n        var pixelLen = pixels.length;\n        var minOpacity = this.minOpacity;\n        var maxOpacity = this.maxOpacity;\n        var diffOpacity = maxOpacity - minOpacity;\n\n        while (offset < pixelLen) {\n            var alpha = pixels[offset + 3] / 256;\n            var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4;\n            // Simple optimize to ignore the empty data\n            if (alpha > 0) {\n                var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange;\n                // Any alpha > 0 will be mapped to [minOpacity, maxOpacity]\n                alpha > 0 && (alpha = alpha * diffOpacity + minOpacity);\n                pixels[offset++] = gradient[gradientOffset];\n                pixels[offset++] = gradient[gradientOffset + 1];\n                pixels[offset++] = gradient[gradientOffset + 2];\n                pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256;\n            }\n            else {\n                offset += 4;\n            }\n        }\n        ctx.putImageData(imageData, 0, 0);\n\n        return canvas;\n    },\n\n    /**\n     * get canvas of a black circle brush used for canvas to draw later\n     * @private\n     * @returns {Object} circle brush canvas\n     */\n    _getBrush: function () {\n        var brushCanvas = this._brushCanvas || (this._brushCanvas = createCanvas());\n        // set brush size\n        var r = this.pointSize + this.blurSize;\n        var d = r * 2;\n        brushCanvas.width = d;\n        brushCanvas.height = d;\n\n        var ctx = brushCanvas.getContext('2d');\n        ctx.clearRect(0, 0, d, d);\n\n        // in order to render shadow without the distinct circle,\n        // draw the distinct circle in an invisible place,\n        // and use shadowOffset to draw shadow in the center of the canvas\n        ctx.shadowOffsetX = d;\n        ctx.shadowBlur = this.blurSize;\n        // draw the shadow in black, and use alpha and shadow blur to generate\n        // color in color map\n        ctx.shadowColor = '#000';\n\n        // draw circle in the left to the canvas\n        ctx.beginPath();\n        ctx.arc(-r, r, this.pointSize, 0, Math.PI * 2, true);\n        ctx.closePath();\n        ctx.fill();\n        return brushCanvas;\n    },\n\n    /**\n     * get gradient color map\n     * @private\n     */\n    _getGradient: function (data, colorFunc, state) {\n        var gradientPixels = this._gradientPixels;\n        var pixelsSingleState = gradientPixels[state] || (gradientPixels[state] = new Uint8ClampedArray(256 * 4));\n        var color = [0, 0, 0, 0];\n        var off = 0;\n        for (var i = 0; i < 256; i++) {\n            colorFunc[state](i / 255, true, color);\n            pixelsSingleState[off++] = color[0];\n            pixelsSingleState[off++] = color[1];\n            pixelsSingleState[off++] = color[2];\n            pixelsSingleState[off++] = color[3];\n        }\n        return pixelsSingleState;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getIsInPiecewiseRange(dataExtent, pieceList, selected) {\n    var dataSpan = dataExtent[1] - dataExtent[0];\n    pieceList = map(pieceList, function (piece) {\n        return {\n            interval: [\n                (piece.interval[0] - dataExtent[0]) / dataSpan,\n                (piece.interval[1] - dataExtent[0]) / dataSpan\n            ]\n        };\n    });\n    var len = pieceList.length;\n    var lastIndex = 0;\n\n    return function (val) {\n        // Try to find in the location of the last found\n        for (var i = lastIndex; i < len; i++) {\n            var interval = pieceList[i].interval;\n            if (interval[0] <= val && val <= interval[1]) {\n                lastIndex = i;\n                break;\n            }\n        }\n        if (i === len) { // Not found, back interation\n            for (var i = lastIndex - 1; i >= 0; i--) {\n                var interval = pieceList[i].interval;\n                if (interval[0] <= val && val <= interval[1]) {\n                    lastIndex = i;\n                    break;\n                }\n            }\n        }\n        return i >= 0 && i < len && selected[i];\n    };\n}\n\nfunction getIsInContinuousRange(dataExtent, range) {\n    var dataSpan = dataExtent[1] - dataExtent[0];\n    range = [\n        (range[0] - dataExtent[0]) / dataSpan,\n        (range[1] - dataExtent[0]) / dataSpan\n    ];\n    return function (val) {\n        return val >= range[0] && val <= range[1];\n    };\n}\n\nfunction isGeoCoordSys(coordSys) {\n    var dimensions = coordSys.dimensions;\n    // Not use coorSys.type === 'geo' because coordSys maybe extended\n    return dimensions[0] === 'lng' && dimensions[1] === 'lat';\n}\n\nextendChartView({\n\n    type: 'heatmap',\n\n    render: function (seriesModel, ecModel, api) {\n        var visualMapOfThisSeries;\n        ecModel.eachComponent('visualMap', function (visualMap) {\n            visualMap.eachTargetSeries(function (targetSeries) {\n                if (targetSeries === seriesModel) {\n                    visualMapOfThisSeries = visualMap;\n                }\n            });\n        });\n\n        if (__DEV__) {\n            if (!visualMapOfThisSeries) {\n                throw new Error('Heatmap must use with visualMap');\n            }\n        }\n\n        this.group.removeAll();\n\n        this._incrementalDisplayable = null;\n\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar') {\n            this._renderOnCartesianAndCalendar(seriesModel, api, 0, seriesModel.getData().count());\n        }\n        else if (isGeoCoordSys(coordSys)) {\n            this._renderOnGeo(\n                coordSys, seriesModel, visualMapOfThisSeries, api\n            );\n        }\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this.group.removeAll();\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys) {\n            this._renderOnCartesianAndCalendar(seriesModel, api, params.start, params.end, true);\n        }\n    },\n\n    _renderOnCartesianAndCalendar: function (seriesModel, api, start, end, incremental) {\n\n        var coordSys = seriesModel.coordinateSystem;\n        var width;\n        var height;\n\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n\n            if (__DEV__) {\n                if (!(xAxis.type === 'category' && yAxis.type === 'category')) {\n                    throw new Error('Heatmap on cartesian must have two category axes');\n                }\n                if (!(xAxis.onBand && yAxis.onBand)) {\n                    throw new Error('Heatmap on cartesian must have two axes with boundaryGap true');\n                }\n            }\n\n            width = xAxis.getBandWidth();\n            height = yAxis.getBandWidth();\n        }\n\n        var group = this.group;\n        var data = seriesModel.getData();\n\n        var itemStyleQuery = 'itemStyle';\n        var hoverItemStyleQuery = 'emphasis.itemStyle';\n        var labelQuery = 'label';\n        var hoverLabelQuery = 'emphasis.label';\n        var style = seriesModel.getModel(itemStyleQuery).getItemStyle(['color']);\n        var hoverStl = seriesModel.getModel(hoverItemStyleQuery).getItemStyle();\n        var labelModel = seriesModel.getModel(labelQuery);\n        var hoverLabelModel = seriesModel.getModel(hoverLabelQuery);\n        var coordSysType = coordSys.type;\n\n\n        var dataDims = coordSysType === 'cartesian2d'\n            ? [\n                data.mapDimension('x'),\n                data.mapDimension('y'),\n                data.mapDimension('value')\n            ]\n            : [\n                data.mapDimension('time'),\n                data.mapDimension('value')\n            ];\n\n        for (var idx = start; idx < end; idx++) {\n            var rect;\n\n            if (coordSysType === 'cartesian2d') {\n                // Ignore empty data\n                if (isNaN(data.get(dataDims[2], idx))) {\n                    continue;\n                }\n\n                var point = coordSys.dataToPoint([\n                    data.get(dataDims[0], idx),\n                    data.get(dataDims[1], idx)\n                ]);\n\n                rect = new Rect({\n                    shape: {\n                        x: point[0] - width / 2,\n                        y: point[1] - height / 2,\n                        width: width,\n                        height: height\n                    },\n                    style: {\n                        fill: data.getItemVisual(idx, 'color'),\n                        opacity: data.getItemVisual(idx, 'opacity')\n                    }\n                });\n            }\n            else {\n                // Ignore empty data\n                if (isNaN(data.get(dataDims[1], idx))) {\n                    continue;\n                }\n\n                rect = new Rect({\n                    z2: 1,\n                    shape: coordSys.dataToRect([data.get(dataDims[0], idx)]).contentShape,\n                    style: {\n                        fill: data.getItemVisual(idx, 'color'),\n                        opacity: data.getItemVisual(idx, 'opacity')\n                    }\n                });\n            }\n\n            var itemModel = data.getItemModel(idx);\n\n            // Optimization for large datset\n            if (data.hasItemOption) {\n                style = itemModel.getModel(itemStyleQuery).getItemStyle(['color']);\n                hoverStl = itemModel.getModel(hoverItemStyleQuery).getItemStyle();\n                labelModel = itemModel.getModel(labelQuery);\n                hoverLabelModel = itemModel.getModel(hoverLabelQuery);\n            }\n\n            var rawValue = seriesModel.getRawValue(idx);\n            var defaultText = '-';\n            if (rawValue && rawValue[2] != null) {\n                defaultText = rawValue[2];\n            }\n\n            setLabelStyle(\n                style, hoverStl, labelModel, hoverLabelModel,\n                {\n                    labelFetcher: seriesModel,\n                    labelDataIndex: idx,\n                    defaultText: defaultText,\n                    isRectText: true\n                }\n            );\n\n            rect.setStyle(style);\n            setHoverStyle(rect, data.hasItemOption ? hoverStl : extend({}, hoverStl));\n\n            rect.incremental = incremental;\n            // PENDING\n            if (incremental) {\n                // Rect must use hover layer if it's incremental.\n                rect.useHoverLayer = true;\n            }\n\n            group.add(rect);\n            data.setItemGraphicEl(idx, rect);\n        }\n    },\n\n    _renderOnGeo: function (geo, seriesModel, visualMapModel, api) {\n        var inRangeVisuals = visualMapModel.targetVisuals.inRange;\n        var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange;\n        // if (!visualMapping) {\n        //     throw new Error('Data range must have color visuals');\n        // }\n\n        var data = seriesModel.getData();\n        var hmLayer = this._hmLayer || (this._hmLayer || new Heatmap());\n        hmLayer.blurSize = seriesModel.get('blurSize');\n        hmLayer.pointSize = seriesModel.get('pointSize');\n        hmLayer.minOpacity = seriesModel.get('minOpacity');\n        hmLayer.maxOpacity = seriesModel.get('maxOpacity');\n\n        var rect = geo.getViewRect().clone();\n        var roamTransform = geo.getRoamTransform();\n        rect.applyTransform(roamTransform);\n\n        // Clamp on viewport\n        var x = Math.max(rect.x, 0);\n        var y = Math.max(rect.y, 0);\n        var x2 = Math.min(rect.width + rect.x, api.getWidth());\n        var y2 = Math.min(rect.height + rect.y, api.getHeight());\n        var width = x2 - x;\n        var height = y2 - y;\n\n        var dims = [\n            data.mapDimension('lng'),\n            data.mapDimension('lat'),\n            data.mapDimension('value')\n        ];\n\n        var points = data.mapArray(dims, function (lng, lat, value) {\n            var pt = geo.dataToPoint([lng, lat]);\n            pt[0] -= x;\n            pt[1] -= y;\n            pt.push(value);\n            return pt;\n        });\n\n        var dataExtent = visualMapModel.getExtent();\n        var isInRange = visualMapModel.type === 'visualMap.continuous'\n            ? getIsInContinuousRange(dataExtent, visualMapModel.option.range)\n            : getIsInPiecewiseRange(\n                dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected\n            );\n\n        hmLayer.update(\n            points, width, height,\n            inRangeVisuals.color.getNormalizer(),\n            {\n                inRange: inRangeVisuals.color.getColorMapper(),\n                outOfRange: outOfRangeVisuals.color.getColorMapper()\n            },\n            isInRange\n        );\n        var img = new ZImage({\n            style: {\n                width: width,\n                height: height,\n                x: x,\n                y: y,\n                image: hmLayer.canvas\n            },\n            silent: true\n        });\n        this.group.add(img);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PictorialBarSeries = BaseBarSeries.extend({\n\n    type: 'series.pictorialBar',\n\n    dependencies: ['grid'],\n\n    defaultOption: {\n        symbol: 'circle',     // Customized bar shape\n        symbolSize: null,     // Can be ['100%', '100%'], null means auto.\n        symbolRotate: null,\n\n        symbolPosition: null, // 'start' or 'end' or 'center', null means auto.\n        symbolOffset: null,\n        symbolMargin: null,   // start margin and end margin. Can be a number or a percent string.\n                                // Auto margin by defualt.\n        symbolRepeat: false,  // false/null/undefined, means no repeat.\n                                // Can be true, means auto calculate repeat times and cut by data.\n                                // Can be a number, specifies repeat times, and do not cut by data.\n                                // Can be 'fixed', means auto calculate repeat times but do not cut by data.\n        symbolRepeatDirection: 'end', // 'end' means from 'start' to 'end'.\n\n        symbolClip: false,\n        symbolBoundingData: null, // Can be 60 or -40 or [-40, 60]\n        symbolPatternSize: 400, // 400 * 400 px\n\n        barGap: '-100%',      // In most case, overlap is needed.\n\n        // z can be set in data item, which is z2 actually.\n\n        // Disable progressive\n        progressive: 0,\n        hoverAnimation: false // Open only when needed.\n    },\n\n    getInitialData: function (option) {\n        // Disable stack.\n        option.stack = null;\n        return PictorialBarSeries.superApply(this, 'getInitialData', arguments);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY$1 = ['itemStyle', 'borderWidth'];\n\n// index: +isHorizontal\nvar LAYOUT_ATTRS = [\n    {xy: 'x', wh: 'width', index: 0, posDesc: ['left', 'right']},\n    {xy: 'y', wh: 'height', index: 1, posDesc: ['top', 'bottom']}\n];\n\nvar pathForLineWidth = new Circle();\n\nvar BarView$1 = extendChartView({\n\n    type: 'pictorialBar',\n\n    render: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var isHorizontal = !!baseAxis.isHorizontal();\n        var coordSysRect = cartesian.grid.getRect();\n\n        var opt = {\n            ecSize: {width: api.getWidth(), height: api.getHeight()},\n            seriesModel: seriesModel,\n            coordSys: cartesian,\n            coordSysExtent: [\n                [coordSysRect.x, coordSysRect.x + coordSysRect.width],\n                [coordSysRect.y, coordSysRect.y + coordSysRect.height]\n            ],\n            isHorizontal: isHorizontal,\n            valueDim: LAYOUT_ATTRS[+isHorizontal],\n            categoryDim: LAYOUT_ATTRS[1 - isHorizontal]\n        };\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = getItemModel(data, dataIndex);\n                var symbolMeta = getSymbolMeta(data, dataIndex, itemModel, opt);\n\n                var bar = createBar(data, opt, symbolMeta);\n\n                data.setItemGraphicEl(dataIndex, bar);\n                group.add(bar);\n\n                updateCommon$1(bar, opt, symbolMeta);\n            })\n            .update(function (newIndex, oldIndex) {\n                var bar = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(bar);\n                    return;\n                }\n\n                var itemModel = getItemModel(data, newIndex);\n                var symbolMeta = getSymbolMeta(data, newIndex, itemModel, opt);\n\n                var pictorialShapeStr = getShapeStr(data, symbolMeta);\n                if (bar && pictorialShapeStr !== bar.__pictorialShapeStr) {\n                    group.remove(bar);\n                    data.setItemGraphicEl(newIndex, null);\n                    bar = null;\n                }\n\n                if (bar) {\n                    updateBar(bar, opt, symbolMeta);\n                }\n                else {\n                    bar = createBar(data, opt, symbolMeta, true);\n                }\n\n                data.setItemGraphicEl(newIndex, bar);\n                bar.__pictorialSymbolMeta = symbolMeta;\n                // Add back\n                group.add(bar);\n\n                updateCommon$1(bar, opt, symbolMeta);\n            })\n            .remove(function (dataIndex) {\n                var bar = oldData.getItemGraphicEl(dataIndex);\n                bar && removeBar(oldData, dataIndex, bar.__pictorialSymbolMeta.animationModel, bar);\n            })\n            .execute();\n\n        this._data = data;\n\n        return this.group;\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel, api) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel.get('animation')) {\n            if (data) {\n                data.eachItemGraphicEl(function (bar) {\n                    removeBar(data, bar.dataIndex, ecModel, bar);\n                });\n            }\n        }\n        else {\n            group.removeAll();\n        }\n    }\n});\n\n\n// Set or calculate default value about symbol, and calculate layout info.\nfunction getSymbolMeta(data, dataIndex, itemModel, opt) {\n    var layout = data.getItemLayout(dataIndex);\n    var symbolRepeat = itemModel.get('symbolRepeat');\n    var symbolClip = itemModel.get('symbolClip');\n    var symbolPosition = itemModel.get('symbolPosition') || 'start';\n    var symbolRotate = itemModel.get('symbolRotate');\n    var rotation = (symbolRotate || 0) * Math.PI / 180 || 0;\n    var symbolPatternSize = itemModel.get('symbolPatternSize') || 2;\n    var isAnimationEnabled = itemModel.isAnimationEnabled();\n\n    var symbolMeta = {\n        dataIndex: dataIndex,\n        layout: layout,\n        itemModel: itemModel,\n        symbolType: data.getItemVisual(dataIndex, 'symbol') || 'circle',\n        color: data.getItemVisual(dataIndex, 'color'),\n        symbolClip: symbolClip,\n        symbolRepeat: symbolRepeat,\n        symbolRepeatDirection: itemModel.get('symbolRepeatDirection'),\n        symbolPatternSize: symbolPatternSize,\n        rotation: rotation,\n        animationModel: isAnimationEnabled ? itemModel : null,\n        hoverAnimation: isAnimationEnabled && itemModel.get('hoverAnimation'),\n        z2: itemModel.getShallow('z', true) || 0\n    };\n\n    prepareBarLength(itemModel, symbolRepeat, layout, opt, symbolMeta);\n\n    prepareSymbolSize(\n        data, dataIndex, layout, symbolRepeat, symbolClip, symbolMeta.boundingLength,\n        symbolMeta.pxSign, symbolPatternSize, opt, symbolMeta\n    );\n\n    prepareLineWidth(itemModel, symbolMeta.symbolScale, rotation, opt, symbolMeta);\n\n    var symbolSize = symbolMeta.symbolSize;\n    var symbolOffset = itemModel.get('symbolOffset');\n    if (isArray(symbolOffset)) {\n        symbolOffset = [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ];\n    }\n\n    prepareLayoutInfo(\n        itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset,\n        symbolPosition, symbolMeta.valueLineWidth, symbolMeta.boundingLength, symbolMeta.repeatCutLength,\n        opt, symbolMeta\n    );\n\n    return symbolMeta;\n}\n\n// bar length can be negative.\nfunction prepareBarLength(itemModel, symbolRepeat, layout, opt, output) {\n    var valueDim = opt.valueDim;\n    var symbolBoundingData = itemModel.get('symbolBoundingData');\n    var valueAxis = opt.coordSys.getOtherAxis(opt.coordSys.getBaseAxis());\n    var zeroPx = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    var pxSignIdx = 1 - +(layout[valueDim.wh] <= 0);\n    var boundingLength;\n\n    if (isArray(symbolBoundingData)) {\n        var symbolBoundingExtent = [\n            convertToCoordOnAxis(valueAxis, symbolBoundingData[0]) - zeroPx,\n            convertToCoordOnAxis(valueAxis, symbolBoundingData[1]) - zeroPx\n        ];\n        symbolBoundingExtent[1] < symbolBoundingExtent[0] && (symbolBoundingExtent.reverse());\n        boundingLength = symbolBoundingExtent[pxSignIdx];\n    }\n    else if (symbolBoundingData != null) {\n        boundingLength = convertToCoordOnAxis(valueAxis, symbolBoundingData) - zeroPx;\n    }\n    else if (symbolRepeat) {\n        boundingLength = opt.coordSysExtent[valueDim.index][pxSignIdx] - zeroPx;\n    }\n    else {\n        boundingLength = layout[valueDim.wh];\n    }\n\n    output.boundingLength = boundingLength;\n\n    if (symbolRepeat) {\n        output.repeatCutLength = layout[valueDim.wh];\n    }\n\n    output.pxSign = boundingLength > 0 ? 1 : boundingLength < 0 ? -1 : 0;\n}\n\nfunction convertToCoordOnAxis(axis, value) {\n    return axis.toGlobalCoord(axis.dataToCoord(axis.scale.parse(value)));\n}\n\n// Support ['100%', '100%']\nfunction prepareSymbolSize(\n    data, dataIndex, layout, symbolRepeat, symbolClip, boundingLength,\n    pxSign, symbolPatternSize, opt, output\n) {\n    var valueDim = opt.valueDim;\n    var categoryDim = opt.categoryDim;\n    var categorySize = Math.abs(layout[categoryDim.wh]);\n\n    var symbolSize = data.getItemVisual(dataIndex, 'symbolSize');\n    if (isArray(symbolSize)) {\n        symbolSize = symbolSize.slice();\n    }\n    else {\n        if (symbolSize == null) {\n            symbolSize = '100%';\n        }\n        symbolSize = [symbolSize, symbolSize];\n    }\n\n    // Note: percentage symbolSize (like '100%') do not consider lineWidth, because it is\n    // to complicated to calculate real percent value if considering scaled lineWidth.\n    // So the actual size will bigger than layout size if lineWidth is bigger than zero,\n    // which can be tolerated in pictorial chart.\n\n    symbolSize[categoryDim.index] = parsePercent$1(\n        symbolSize[categoryDim.index],\n        categorySize\n    );\n    symbolSize[valueDim.index] = parsePercent$1(\n        symbolSize[valueDim.index],\n        symbolRepeat ? categorySize : Math.abs(boundingLength)\n    );\n\n    output.symbolSize = symbolSize;\n\n    // If x or y is less than zero, show reversed shape.\n    var symbolScale = output.symbolScale = [\n        symbolSize[0] / symbolPatternSize,\n        symbolSize[1] / symbolPatternSize\n    ];\n    // Follow convention, 'right' and 'top' is the normal scale.\n    symbolScale[valueDim.index] *= (opt.isHorizontal ? -1 : 1) * pxSign;\n}\n\nfunction prepareLineWidth(itemModel, symbolScale, rotation, opt, output) {\n    // In symbols are drawn with scale, so do not need to care about the case that width\n    // or height are too small. But symbol use strokeNoScale, where acture lineWidth should\n    // be calculated.\n    var valueLineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY$1) || 0;\n\n    if (valueLineWidth) {\n        pathForLineWidth.attr({\n            scale: symbolScale.slice(),\n            rotation: rotation\n        });\n        pathForLineWidth.updateTransform();\n        valueLineWidth /= pathForLineWidth.getLineScale();\n        valueLineWidth *= symbolScale[opt.valueDim.index];\n    }\n\n    output.valueLineWidth = valueLineWidth;\n}\n\nfunction prepareLayoutInfo(\n    itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset,\n    symbolPosition, valueLineWidth, boundingLength, repeatCutLength, opt, output\n) {\n    var categoryDim = opt.categoryDim;\n    var valueDim = opt.valueDim;\n    var pxSign = output.pxSign;\n\n    var unitLength = Math.max(symbolSize[valueDim.index] + valueLineWidth, 0);\n    var pathLen = unitLength;\n\n    // Note: rotation will not effect the layout of symbols, because user may\n    // want symbols to rotate on its center, which should not be translated\n    // when rotating.\n\n    if (symbolRepeat) {\n        var absBoundingLength = Math.abs(boundingLength);\n\n        var symbolMargin = retrieve(itemModel.get('symbolMargin'), '15%') + '';\n        var hasEndGap = false;\n        if (symbolMargin.lastIndexOf('!') === symbolMargin.length - 1) {\n            hasEndGap = true;\n            symbolMargin = symbolMargin.slice(0, symbolMargin.length - 1);\n        }\n        symbolMargin = parsePercent$1(symbolMargin, symbolSize[valueDim.index]);\n\n        var uLenWithMargin = Math.max(unitLength + symbolMargin * 2, 0);\n\n        // When symbol margin is less than 0, margin at both ends will be subtracted\n        // to ensure that all of the symbols will not be overflow the given area.\n        var endFix = hasEndGap ? 0 : symbolMargin * 2;\n\n        // Both final repeatTimes and final symbolMargin area calculated based on\n        // boundingLength.\n        var repeatSpecified = isNumeric(symbolRepeat);\n        var repeatTimes = repeatSpecified\n            ? symbolRepeat\n            : toIntTimes((absBoundingLength + endFix) / uLenWithMargin);\n\n        // Adjust calculate margin, to ensure each symbol is displayed\n        // entirely in the given layout area.\n        var mDiff = absBoundingLength - repeatTimes * unitLength;\n        symbolMargin = mDiff / 2 / (hasEndGap ? repeatTimes : repeatTimes - 1);\n        uLenWithMargin = unitLength + symbolMargin * 2;\n        endFix = hasEndGap ? 0 : symbolMargin * 2;\n\n        // Update repeatTimes when not all symbol will be shown.\n        if (!repeatSpecified && symbolRepeat !== 'fixed') {\n            repeatTimes = repeatCutLength\n                ? toIntTimes((Math.abs(repeatCutLength) + endFix) / uLenWithMargin)\n                : 0;\n        }\n\n        pathLen = repeatTimes * uLenWithMargin - endFix;\n        output.repeatTimes = repeatTimes;\n        output.symbolMargin = symbolMargin;\n    }\n\n    var sizeFix = pxSign * (pathLen / 2);\n    var pathPosition = output.pathPosition = [];\n    pathPosition[categoryDim.index] = layout[categoryDim.wh] / 2;\n    pathPosition[valueDim.index] = symbolPosition === 'start'\n        ? sizeFix\n        : symbolPosition === 'end'\n        ? boundingLength - sizeFix\n        : boundingLength / 2; // 'center'\n    if (symbolOffset) {\n        pathPosition[0] += symbolOffset[0];\n        pathPosition[1] += symbolOffset[1];\n    }\n\n    var bundlePosition = output.bundlePosition = [];\n    bundlePosition[categoryDim.index] = layout[categoryDim.xy];\n    bundlePosition[valueDim.index] = layout[valueDim.xy];\n\n    var barRectShape = output.barRectShape = extend({}, layout);\n    barRectShape[valueDim.wh] = pxSign * Math.max(\n        Math.abs(layout[valueDim.wh]), Math.abs(pathPosition[valueDim.index] + sizeFix)\n    );\n    barRectShape[categoryDim.wh] = layout[categoryDim.wh];\n\n    var clipShape = output.clipShape = {};\n    // Consider that symbol may be overflow layout rect.\n    clipShape[categoryDim.xy] = -layout[categoryDim.xy];\n    clipShape[categoryDim.wh] = opt.ecSize[categoryDim.wh];\n    clipShape[valueDim.xy] = 0;\n    clipShape[valueDim.wh] = layout[valueDim.wh];\n}\n\nfunction createPath(symbolMeta) {\n    var symbolPatternSize = symbolMeta.symbolPatternSize;\n    var path = createSymbol(\n        // Consider texture img, make a big size.\n        symbolMeta.symbolType,\n        -symbolPatternSize / 2,\n        -symbolPatternSize / 2,\n        symbolPatternSize,\n        symbolPatternSize,\n        symbolMeta.color\n    );\n    path.attr({\n        culling: true\n    });\n    path.type !== 'image' && path.setStyle({\n        strokeNoScale: true\n    });\n\n    return path;\n}\n\nfunction createOrUpdateRepeatSymbols(bar, opt, symbolMeta, isUpdate) {\n    var bundle = bar.__pictorialBundle;\n    var symbolSize = symbolMeta.symbolSize;\n    var valueLineWidth = symbolMeta.valueLineWidth;\n    var pathPosition = symbolMeta.pathPosition;\n    var valueDim = opt.valueDim;\n    var repeatTimes = symbolMeta.repeatTimes || 0;\n\n    var index = 0;\n    var unit = symbolSize[opt.valueDim.index] + valueLineWidth + symbolMeta.symbolMargin * 2;\n\n    eachPath(bar, function (path) {\n        path.__pictorialAnimationIndex = index;\n        path.__pictorialRepeatTimes = repeatTimes;\n        if (index < repeatTimes) {\n            updateAttr(path, null, makeTarget(index), symbolMeta, isUpdate);\n        }\n        else {\n            updateAttr(path, null, {scale: [0, 0]}, symbolMeta, isUpdate, function () {\n                bundle.remove(path);\n            });\n        }\n\n        updateHoverAnimation(path, symbolMeta);\n\n        index++;\n    });\n\n    for (; index < repeatTimes; index++) {\n        var path = createPath(symbolMeta);\n        path.__pictorialAnimationIndex = index;\n        path.__pictorialRepeatTimes = repeatTimes;\n        bundle.add(path);\n\n        var target = makeTarget(index);\n\n        updateAttr(\n            path,\n            {\n                position: target.position,\n                scale: [0, 0]\n            },\n            {\n                scale: target.scale,\n                rotation: target.rotation\n            },\n            symbolMeta,\n            isUpdate\n        );\n\n        // FIXME\n        // If all emphasis/normal through action.\n        path\n            .on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut);\n\n        updateHoverAnimation(path, symbolMeta);\n    }\n\n    function makeTarget(index) {\n        var position = pathPosition.slice();\n        // (start && pxSign > 0) || (end && pxSign < 0): i = repeatTimes - index\n        // Otherwise: i = index;\n        var pxSign = symbolMeta.pxSign;\n        var i = index;\n        if (symbolMeta.symbolRepeatDirection === 'start' ? pxSign > 0 : pxSign < 0) {\n            i = repeatTimes - 1 - index;\n        }\n        position[valueDim.index] = unit * (i - repeatTimes / 2 + 0.5) + pathPosition[valueDim.index];\n\n        return {\n            position: position,\n            scale: symbolMeta.symbolScale.slice(),\n            rotation: symbolMeta.rotation\n        };\n    }\n\n    function onMouseOver() {\n        eachPath(bar, function (path) {\n            path.trigger('emphasis');\n        });\n    }\n\n    function onMouseOut() {\n        eachPath(bar, function (path) {\n            path.trigger('normal');\n        });\n    }\n}\n\nfunction createOrUpdateSingleSymbol(bar, opt, symbolMeta, isUpdate) {\n    var bundle = bar.__pictorialBundle;\n    var mainPath = bar.__pictorialMainPath;\n\n    if (!mainPath) {\n        mainPath = bar.__pictorialMainPath = createPath(symbolMeta);\n        bundle.add(mainPath);\n\n        updateAttr(\n            mainPath,\n            {\n                position: symbolMeta.pathPosition.slice(),\n                scale: [0, 0],\n                rotation: symbolMeta.rotation\n            },\n            {\n                scale: symbolMeta.symbolScale.slice()\n            },\n            symbolMeta,\n            isUpdate\n        );\n\n        mainPath\n            .on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut);\n    }\n    else {\n        updateAttr(\n            mainPath,\n            null,\n            {\n                position: symbolMeta.pathPosition.slice(),\n                scale: symbolMeta.symbolScale.slice(),\n                rotation: symbolMeta.rotation\n            },\n            symbolMeta,\n            isUpdate\n        );\n    }\n\n    updateHoverAnimation(mainPath, symbolMeta);\n\n    function onMouseOver() {\n        this.trigger('emphasis');\n    }\n\n    function onMouseOut() {\n        this.trigger('normal');\n    }\n}\n\n// bar rect is used for label.\nfunction createOrUpdateBarRect(bar, symbolMeta, isUpdate) {\n    var rectShape = extend({}, symbolMeta.barRectShape);\n\n    var barRect = bar.__pictorialBarRect;\n    if (!barRect) {\n        barRect = bar.__pictorialBarRect = new Rect({\n            z2: 2,\n            shape: rectShape,\n            silent: true,\n            style: {\n                stroke: 'transparent',\n                fill: 'transparent',\n                lineWidth: 0\n            }\n        });\n\n        bar.add(barRect);\n    }\n    else {\n        updateAttr(barRect, null, {shape: rectShape}, symbolMeta, isUpdate);\n    }\n}\n\nfunction createOrUpdateClip(bar, opt, symbolMeta, isUpdate) {\n    // If not clip, symbol will be remove and rebuilt.\n    if (symbolMeta.symbolClip) {\n        var clipPath = bar.__pictorialClipPath;\n        var clipShape = extend({}, symbolMeta.clipShape);\n        var valueDim = opt.valueDim;\n        var animationModel = symbolMeta.animationModel;\n        var dataIndex = symbolMeta.dataIndex;\n\n        if (clipPath) {\n            updateProps(\n                clipPath, {shape: clipShape}, animationModel, dataIndex\n            );\n        }\n        else {\n            clipShape[valueDim.wh] = 0;\n            clipPath = new Rect({shape: clipShape});\n            bar.__pictorialBundle.setClipPath(clipPath);\n            bar.__pictorialClipPath = clipPath;\n\n            var target = {};\n            target[valueDim.wh] = symbolMeta.clipShape[valueDim.wh];\n\n            graphic[isUpdate ? 'updateProps' : 'initProps'](\n                clipPath, {shape: target}, animationModel, dataIndex\n            );\n        }\n    }\n}\n\nfunction getItemModel(data, dataIndex) {\n    var itemModel = data.getItemModel(dataIndex);\n    itemModel.getAnimationDelayParams = getAnimationDelayParams;\n    itemModel.isAnimationEnabled = isAnimationEnabled;\n    return itemModel;\n}\n\nfunction getAnimationDelayParams(path) {\n    // The order is the same as the z-order, see `symbolRepeatDiretion`.\n    return {\n        index: path.__pictorialAnimationIndex,\n        count: path.__pictorialRepeatTimes\n    };\n}\n\nfunction isAnimationEnabled() {\n    // `animation` prop can be set on itemModel in pictorial bar chart.\n    return this.parentModel.isAnimationEnabled() && !!this.getShallow('animation');\n}\n\nfunction updateHoverAnimation(path, symbolMeta) {\n    path.off('emphasis').off('normal');\n\n    var scale = symbolMeta.symbolScale.slice();\n\n    symbolMeta.hoverAnimation && path\n        .on('emphasis', function () {\n            this.animateTo({\n                scale: [scale[0] * 1.1, scale[1] * 1.1]\n            }, 400, 'elasticOut');\n        })\n        .on('normal', function () {\n            this.animateTo({\n                scale: scale.slice()\n            }, 400, 'elasticOut');\n        });\n}\n\nfunction createBar(data, opt, symbolMeta, isUpdate) {\n    // bar is the main element for each data.\n    var bar = new Group();\n    // bundle is used for location and clip.\n    var bundle = new Group();\n    bar.add(bundle);\n    bar.__pictorialBundle = bundle;\n    bundle.attr('position', symbolMeta.bundlePosition.slice());\n\n    if (symbolMeta.symbolRepeat) {\n        createOrUpdateRepeatSymbols(bar, opt, symbolMeta);\n    }\n    else {\n        createOrUpdateSingleSymbol(bar, opt, symbolMeta);\n    }\n\n    createOrUpdateBarRect(bar, symbolMeta, isUpdate);\n\n    createOrUpdateClip(bar, opt, symbolMeta, isUpdate);\n\n    bar.__pictorialShapeStr = getShapeStr(data, symbolMeta);\n    bar.__pictorialSymbolMeta = symbolMeta;\n\n    return bar;\n}\n\nfunction updateBar(bar, opt, symbolMeta) {\n    var animationModel = symbolMeta.animationModel;\n    var dataIndex = symbolMeta.dataIndex;\n    var bundle = bar.__pictorialBundle;\n\n    updateProps(\n        bundle, {position: symbolMeta.bundlePosition.slice()}, animationModel, dataIndex\n    );\n\n    if (symbolMeta.symbolRepeat) {\n        createOrUpdateRepeatSymbols(bar, opt, symbolMeta, true);\n    }\n    else {\n        createOrUpdateSingleSymbol(bar, opt, symbolMeta, true);\n    }\n\n    createOrUpdateBarRect(bar, symbolMeta, true);\n\n    createOrUpdateClip(bar, opt, symbolMeta, true);\n}\n\nfunction removeBar(data, dataIndex, animationModel, bar) {\n    // Not show text when animating\n    var labelRect = bar.__pictorialBarRect;\n    labelRect && (labelRect.style.text = null);\n\n    var pathes = [];\n    eachPath(bar, function (path) {\n        pathes.push(path);\n    });\n    bar.__pictorialMainPath && pathes.push(bar.__pictorialMainPath);\n\n    // I do not find proper remove animation for clip yet.\n    bar.__pictorialClipPath && (animationModel = null);\n\n    each$1(pathes, function (path) {\n        updateProps(\n            path, {scale: [0, 0]}, animationModel, dataIndex,\n            function () {\n                bar.parent && bar.parent.remove(bar);\n            }\n        );\n    });\n\n    data.setItemGraphicEl(dataIndex, null);\n}\n\nfunction getShapeStr(data, symbolMeta) {\n    return [\n        data.getItemVisual(symbolMeta.dataIndex, 'symbol') || 'none',\n        !!symbolMeta.symbolRepeat,\n        !!symbolMeta.symbolClip\n    ].join(':');\n}\n\nfunction eachPath(bar, cb, context) {\n    // Do not use Group#eachChild, because it do not support remove.\n    each$1(bar.__pictorialBundle.children(), function (el) {\n        el !== bar.__pictorialBarRect && cb.call(context, el);\n    });\n}\n\nfunction updateAttr(el, immediateAttrs, animationAttrs, symbolMeta, isUpdate, cb) {\n    immediateAttrs && el.attr(immediateAttrs);\n    // when symbolCip used, only clip path has init animation, otherwise it would be weird effect.\n    if (symbolMeta.symbolClip && !isUpdate) {\n        animationAttrs && el.attr(animationAttrs);\n    }\n    else {\n        animationAttrs && graphic[isUpdate ? 'updateProps' : 'initProps'](\n            el, animationAttrs, symbolMeta.animationModel, symbolMeta.dataIndex, cb\n        );\n    }\n}\n\nfunction updateCommon$1(bar, opt, symbolMeta) {\n    var color = symbolMeta.color;\n    var dataIndex = symbolMeta.dataIndex;\n    var itemModel = symbolMeta.itemModel;\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var normalStyle = itemModel.getModel('itemStyle').getItemStyle(['color']);\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n    var cursorStyle = itemModel.getShallow('cursor');\n\n    eachPath(bar, function (path) {\n        // PENDING setColor should be before setStyle!!!\n        path.setColor(color);\n        path.setStyle(defaults(\n            {\n                fill: color,\n                opacity: symbolMeta.opacity\n            },\n            normalStyle\n        ));\n        setHoverStyle(path, hoverStyle);\n\n        cursorStyle && (path.cursor = cursorStyle);\n        path.z2 = symbolMeta.z2;\n    });\n\n    var barRectHoverStyle = {};\n    var barPositionOutside = opt.valueDim.posDesc[+(symbolMeta.boundingLength > 0)];\n    var barRect = bar.__pictorialBarRect;\n\n    setLabel(\n        barRect.style, barRectHoverStyle, itemModel,\n        color, opt.seriesModel, dataIndex, barPositionOutside\n    );\n\n    setHoverStyle(barRect, barRectHoverStyle);\n}\n\nfunction toIntTimes(times) {\n    var roundedTimes = Math.round(times);\n    // Escapse accurate error\n    return Math.abs(times - roundedTimes) < 1e-4\n        ? roundedTimes\n        : Math.ceil(times);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(\n    layout, 'pictorialBar'\n));\nregisterVisual(visualSymbol('pictorialBar', 'roundRect'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor  module:echarts/coord/single/SingleAxis\n * @extends {module:echarts/coord/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar SingleAxis = function (dim, scale, coordExtent, axisType, position) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     * - 'category'\n     * - 'value'\n     * - 'time'\n     * - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     *  @type {string}\n     */\n    this.position = position || 'bottom';\n\n    /**\n     * Axis orient\n     *  - 'horizontal'\n     *  - 'vertical'\n     * @type {[type]}\n     */\n    this.orient = null;\n\n};\n\nSingleAxis.prototype = {\n\n    constructor: SingleAxis,\n\n    /**\n     * Axis model\n     * @type {module:echarts/coord/single/AxisModel}\n     */\n    model: null,\n\n    /**\n     * Judge the orient of the axis.\n     * @return {boolean}\n     */\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordinateSystem.pointToData(point, clamp)[0];\n    },\n\n    /**\n     * Convert the local coord(processed by dataToCoord())\n     * to global coord(concrete pixel coord).\n     * designated by module:echarts/coord/single/Single.\n     * @type {Function}\n     */\n    toGlobalCoord: null,\n\n    /**\n     * Convert the global coord to local coord.\n     * designated by module:echarts/coord/single/Single.\n     * @type {Function}\n     */\n    toLocalCoord: null\n\n};\n\ninherits(SingleAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Single coordinates system.\n */\n\n/**\n * Create a single coordinates system.\n *\n * @param {module:echarts/coord/single/AxisModel} axisModel\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction Single(axisModel, ecModel, api) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.dimension = 'single';\n\n    /**\n     * Add it just for draw tooltip.\n     *\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    this.dimensions = ['single'];\n\n    /**\n     * @private\n     * @type {module:echarts/coord/single/SingleAxis}.\n     */\n    this._axis = null;\n\n    /**\n     * @private\n     * @type {module:zrender/core/BoundingRect}\n     */\n    this._rect;\n\n    this._init(axisModel, ecModel, api);\n\n    /**\n     * @type {module:echarts/coord/single/AxisModel}\n     */\n    this.model = axisModel;\n}\n\nSingle.prototype = {\n\n    type: 'singleAxis',\n\n    axisPointerEnabled: true,\n\n    constructor: Single,\n\n    /**\n     * Initialize single coordinate system.\n     *\n     * @param  {module:echarts/coord/single/AxisModel} axisModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @private\n     */\n    _init: function (axisModel, ecModel, api) {\n\n        var dim = this.dimension;\n\n        var axis = new SingleAxis(\n            dim,\n            createScaleByModel(axisModel),\n            [0, 0],\n            axisModel.get('type'),\n            axisModel.get('position')\n        );\n\n        var isCategory = axis.type === 'category';\n        axis.onBand = isCategory && axisModel.get('boundaryGap');\n        axis.inverse = axisModel.get('inverse');\n        axis.orient = axisModel.get('orient');\n\n        axisModel.axis = axis;\n        axis.model = axisModel;\n        axis.coordinateSystem = this;\n        this._axis = axis;\n    },\n\n    /**\n     * Update axis scale after data processed\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    update: function (ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            if (seriesModel.coordinateSystem === this) {\n                var data = seriesModel.getData();\n                each$1(data.mapDimension(this.dimension, true), function (dim) {\n                    this._axis.scale.unionExtentFromData(data, dim);\n                }, this);\n                niceScaleExtent(this._axis.scale, this._axis.model);\n            }\n        }, this);\n    },\n\n    /**\n     * Resize the single coordinate system.\n     *\n     * @param  {module:echarts/coord/single/AxisModel} axisModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    resize: function (axisModel, api) {\n        this._rect = getLayoutRect(\n            {\n                left: axisModel.get('left'),\n                top: axisModel.get('top'),\n                right: axisModel.get('right'),\n                bottom: axisModel.get('bottom'),\n                width: axisModel.get('width'),\n                height: axisModel.get('height')\n            },\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        this._adjustAxis();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @private\n     */\n    _adjustAxis: function () {\n\n        var rect = this._rect;\n        var axis = this._axis;\n\n        var isHorizontal = axis.isHorizontal();\n        var extent = isHorizontal ? [0, rect.width] : [0, rect.height];\n        var idx = axis.reverse ? 1 : 0;\n\n        axis.setExtent(extent[idx], extent[1 - idx]);\n\n        this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y);\n\n    },\n\n    /**\n     * @param  {module:echarts/coord/single/SingleAxis} axis\n     * @param  {number} coordBase\n     */\n    _updateAxisTransform: function (axis, coordBase) {\n\n        var axisExtent = axis.getExtent();\n        var extentSum = axisExtent[0] + axisExtent[1];\n        var isHorizontal = axis.isHorizontal();\n\n        axis.toGlobalCoord = isHorizontal\n            ? function (coord) {\n                return coord + coordBase;\n            }\n            : function (coord) {\n                return extentSum - coord + coordBase;\n            };\n\n        axis.toLocalCoord = isHorizontal\n            ? function (coord) {\n                return coord - coordBase;\n            }\n            : function (coord) {\n                return extentSum - coord + coordBase;\n            };\n    },\n\n    /**\n     * Get axis.\n     *\n     * @return {module:echarts/coord/single/SingleAxis}\n     */\n    getAxis: function () {\n        return this._axis;\n    },\n\n    /**\n     * Get axis, add it just for draw tooltip.\n     *\n     * @return {[type]} [description]\n     */\n    getBaseAxis: function () {\n        return this._axis;\n    },\n\n    /**\n     * @return {Array.<module:echarts/coord/Axis>}\n     */\n    getAxes: function () {\n        return [this._axis];\n    },\n\n    /**\n     * @return {Object} {baseAxes: [], otherAxes: []}\n     */\n    getTooltipAxes: function () {\n        return {baseAxes: [this.getAxis()]};\n    },\n\n    /**\n     * If contain point.\n     *\n     * @param  {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var rect = this.getRect();\n        var axis = this.getAxis();\n        var orient = axis.orient;\n        if (orient === 'horizontal') {\n            return axis.contain(axis.toLocalCoord(point[0]))\n            && (point[1] >= rect.y && point[1] <= (rect.y + rect.height));\n        }\n        else {\n            return axis.contain(axis.toLocalCoord(point[1]))\n            && (point[0] >= rect.y && point[0] <= (rect.y + rect.height));\n        }\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToData: function (point) {\n        var axis = this.getAxis();\n        return [axis.coordToData(axis.toLocalCoord(\n            point[axis.orient === 'horizontal' ? 0 : 1]\n        ))];\n    },\n\n    /**\n     * Convert the series data to concrete point.\n     *\n     * @param  {number|Array.<number>} val\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (val) {\n        var axis = this.getAxis();\n        var rect = this.getRect();\n        var pt = [];\n        var idx = axis.orient === 'horizontal' ? 0 : 1;\n\n        if (val instanceof Array) {\n            val = val[0];\n        }\n\n        pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val));\n        pt[1 - idx] = idx === 0 ? (rect.y + rect.height / 2) : (rect.x + rect.width / 2);\n        return pt;\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Single coordinate system creator.\n */\n\n/**\n * Create single coordinate system and inject it into seriesModel.\n *\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Array.<module:echarts/coord/single/Single>}\n */\nfunction create$3(ecModel, api) {\n    var singles = [];\n\n    ecModel.eachComponent('singleAxis', function (axisModel, idx) {\n\n        var single = new Single(axisModel, ecModel, api);\n        single.name = 'single_' + idx;\n        single.resize(axisModel, api);\n        axisModel.coordinateSystem = single;\n        singles.push(single);\n\n    });\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'singleAxis') {\n            var singleAxisModel = ecModel.queryComponents({\n                mainType: 'singleAxis',\n                index: seriesModel.get('singleAxisIndex'),\n                id: seriesModel.get('singleAxisId')\n            })[0];\n            seriesModel.coordinateSystem = singleAxisModel && singleAxisModel.coordinateSystem;\n        }\n    });\n\n    return singles;\n}\n\nCoordinateSystemManager.register('single', {\n    create: create$3,\n    dimensions: Single.prototype.dimensions\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$2(axisModel, opt) {\n    opt = opt || {};\n    var single = axisModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n\n    var axisPosition = axis.position;\n    var orient = axis.orient;\n\n    var rect = single.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n\n    var positionMap = {\n        horizontal: {top: rectBound[2], bottom: rectBound[3]},\n        vertical: {left: rectBound[0], right: rectBound[1]}\n    };\n\n    layout.position = [\n        orient === 'vertical'\n            ? positionMap.vertical[axisPosition]\n            : rectBound[0],\n        orient === 'horizontal'\n            ? positionMap.horizontal[axisPosition]\n            : rectBound[3]\n    ];\n\n    var r = {horizontal: 0, vertical: 1};\n    layout.rotation = Math.PI / 2 * r[orient];\n\n    var directionMap = {top: -1, bottom: 1, right: 1, left: -1};\n\n    layout.labelDirection = layout.tickDirection\n        = layout.nameDirection\n        = directionMap[axisPosition];\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    var labelRotation = opt.rotate;\n    labelRotation == null && (labelRotation = axisModel.get('axisLabel.rotate'));\n    layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation;\n\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar axisBuilderAttrs$2 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\n\nvar selfBuilderAttr = 'splitLine';\n\nvar SingleAxisView = AxisView.extend({\n\n    type: 'singleAxis',\n\n    axisPointerClass: 'SingleAxisPointer',\n\n    render: function (axisModel, ecModel, api, payload) {\n\n        var group = this.group;\n\n        group.removeAll();\n\n        var layout = layout$2(axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs$2, axisBuilder.add, axisBuilder);\n\n        group.add(axisBuilder.getGroup());\n\n        if (axisModel.get(selfBuilderAttr + '.show')) {\n            this['_' + selfBuilderAttr](axisModel);\n        }\n\n        SingleAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    _splitLine: function (axisModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineWidth = lineStyleModel.get('width');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var gridRect = axisModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var splitLines = [];\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        for (var i = 0; i < ticksCoords.length; ++i) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Line(\n                subPixelOptimizeLine({\n                    shape: {\n                        x1: p1[0],\n                        y1: p1[1],\n                        x2: p2[0],\n                        y2: p2[1]\n                    },\n                    style: {\n                        lineWidth: lineWidth\n                    },\n                    silent: true\n                })));\n        }\n\n        for (var i = 0; i < splitLines.length; ++i) {\n            this.group.add(mergePath(splitLines[i], {\n                style: {\n                    stroke: lineColors[i % lineColors.length],\n                    lineDash: lineStyleModel.getLineDash(lineWidth),\n                    lineWidth: lineWidth\n                },\n                silent: true\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel$4 = ComponentModel.extend({\n\n    type: 'singleAxis',\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/single/SingleAxis}\n     */\n    axis: null,\n\n    /**\n     * @type {module:echarts/coord/single/Single}\n     */\n    coordinateSystem: null,\n\n    /**\n     * @override\n     */\n    getCoordSysModel: function () {\n        return this;\n    }\n\n});\n\nvar defaultOption$2 = {\n\n    left: '5%',\n    top: '5%',\n    right: '5%',\n    bottom: '5%',\n\n    type: 'value',\n\n    position: 'bottom',\n\n    orient: 'horizontal',\n\n    axisLine: {\n        show: true,\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        }\n    },\n\n    // Single coordinate system and single axis is the,\n    // which is used as the parent tooltip model.\n    // same model, so we set default tooltip show as true.\n    tooltip: {\n        show: true\n    },\n\n    axisTick: {\n        show: true,\n        length: 6,\n        lineStyle: {\n            width: 2\n        }\n    },\n\n    axisLabel: {\n        show: true,\n        interval: 'auto'\n    },\n\n    splitLine: {\n        show: true,\n        lineStyle: {\n            type: 'dashed',\n            opacity: 0.2\n        }\n    }\n};\n\nfunction getAxisType$2(axisName, option) {\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel$4.prototype, axisModelCommonMixin);\n\naxisModelCreator('single', AxisModel$4, getAxisType$2, defaultOption$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} finder contains {seriesIndex, dataIndex, dataIndexInside}\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} {point: [x, y], el: ...} point Will not be null.\n */\nvar findPointFromSeries = function (finder, ecModel) {\n    var point = [];\n    var seriesIndex = finder.seriesIndex;\n    var seriesModel;\n    if (seriesIndex == null || !(\n        seriesModel = ecModel.getSeriesByIndex(seriesIndex)\n    )) {\n        return {point: []};\n    }\n\n    var data = seriesModel.getData();\n    var dataIndex = queryDataIndex(data, finder);\n    if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) {\n        return {point: []};\n    }\n\n    var el = data.getItemGraphicEl(dataIndex);\n    var coordSys = seriesModel.coordinateSystem;\n\n    if (seriesModel.getTooltipPosition) {\n        point = seriesModel.getTooltipPosition(dataIndex) || [];\n    }\n    else if (coordSys && coordSys.dataToPoint) {\n        point = coordSys.dataToPoint(\n            data.getValues(\n                map(coordSys.dimensions, function (dim) {\n                    return data.mapDimension(dim);\n                }), dataIndex, true\n            )\n        ) || [];\n    }\n    else if (el) {\n        // Use graphic bounding rect\n        var rect = el.getBoundingRect().clone();\n        rect.applyTransform(el.transform);\n        point = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n\n    return {point: point, el: el};\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$14 = each$1;\nvar curry$3 = curry;\nvar inner$9 = makeInner();\n\n/**\n * Basic logic: check all axis, if they do not demand show/highlight,\n * then hide/downplay them.\n *\n * @param {Object} coordSysAxesInfo\n * @param {Object} payload\n * @param {string} [payload.currTrigger] 'click' | 'mousemove' | 'leave'\n * @param {Array.<number>} [payload.x] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Array.<number>} [payload.y] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Object} [payload.seriesIndex] finder, optional, restrict target axes.\n * @param {Object} [payload.dataIndex] finder, restrict target axes.\n * @param {Object} [payload.axesInfo] finder, restrict target axes.\n *        [{\n *          axisDim: 'x'|'y'|'angle'|...,\n *          axisIndex: ...,\n *          value: ...\n *        }, ...]\n * @param {Function} [payload.dispatchAction]\n * @param {Object} [payload.tooltipOption]\n * @param {Object|Array.<number>|Function} [payload.position] Tooltip position,\n *        which can be specified in dispatchAction\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Object} content of event obj for echarts.connect.\n */\nvar axisTrigger = function (payload, ecModel, api) {\n    var currTrigger = payload.currTrigger;\n    var point = [payload.x, payload.y];\n    var finder = payload;\n    var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api);\n    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n    // Pending\n    // See #6121. But we are not able to reproduce it yet.\n    if (!coordSysAxesInfo) {\n        return;\n    }\n\n    if (illegalPoint(point)) {\n        // Used in the default behavior of `connection`: use the sample seriesIndex\n        // and dataIndex. And also used in the tooltipView trigger.\n        point = findPointFromSeries({\n            seriesIndex: finder.seriesIndex,\n            // Do not use dataIndexInside from other ec instance.\n            // FIXME: auto detect it?\n            dataIndex: finder.dataIndex\n        }, ecModel).point;\n    }\n    var isIllegalPoint = illegalPoint(point);\n\n    // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}).\n    // Notice: In this case, it is difficult to get the `point` (which is necessary to show\n    // tooltip, so if point is not given, we just use the point found by sample seriesIndex\n    // and dataIndex.\n    var inputAxesInfo = finder.axesInfo;\n\n    var axesInfo = coordSysAxesInfo.axesInfo;\n    var shouldHide = currTrigger === 'leave' || illegalPoint(point);\n    var outputFinder = {};\n\n    var showValueMap = {};\n    var dataByCoordSys = {list: [], map: {}};\n    var updaters = {\n        showPointer: curry$3(showPointer, showValueMap),\n        showTooltip: curry$3(showTooltip, dataByCoordSys)\n    };\n\n    // Process for triggered axes.\n    each$14(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) {\n        // If a point given, it must be contained by the coordinate system.\n        var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point);\n\n        each$14(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) {\n            var axis = axisInfo.axis;\n            var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo);\n            // If no inputAxesInfo, no axis is restricted.\n            if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) {\n                var val = inputAxisInfo && inputAxisInfo.value;\n                if (val == null && !isIllegalPoint) {\n                    val = axis.pointToData(point);\n                }\n                val != null && processOnAxis(axisInfo, val, updaters, false, outputFinder);\n            }\n        });\n    });\n\n    // Process for linked axes.\n    var linkTriggers = {};\n    each$14(axesInfo, function (tarAxisInfo, tarKey) {\n        var linkGroup = tarAxisInfo.linkGroup;\n\n        // If axis has been triggered in the previous stage, it should not be triggered by link.\n        if (linkGroup && !showValueMap[tarKey]) {\n            each$14(linkGroup.axesInfo, function (srcAxisInfo, srcKey) {\n                var srcValItem = showValueMap[srcKey];\n                // If srcValItem exist, source axis is triggered, so link to target axis.\n                if (srcAxisInfo !== tarAxisInfo && srcValItem) {\n                    var val = srcValItem.value;\n                    linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(\n                        val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)\n                    )));\n                    linkTriggers[tarAxisInfo.key] = val;\n                }\n            });\n        }\n    });\n    each$14(linkTriggers, function (val, tarKey) {\n        processOnAxis(axesInfo[tarKey], val, updaters, true, outputFinder);\n    });\n\n    updateModelActually(showValueMap, axesInfo, outputFinder);\n    dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction);\n    dispatchHighDownActually(axesInfo, dispatchAction, api);\n\n    return outputFinder;\n};\n\nfunction processOnAxis(axisInfo, newValue, updaters, dontSnap, outputFinder) {\n    var axis = axisInfo.axis;\n\n    if (axis.scale.isBlank() || !axis.containData(newValue)) {\n        return;\n    }\n\n    if (!axisInfo.involveSeries) {\n        updaters.showPointer(axisInfo, newValue);\n        return;\n    }\n\n    // Heavy calculation. So put it after axis.containData checking.\n    var payloadInfo = buildPayloadsBySeries(newValue, axisInfo);\n    var payloadBatch = payloadInfo.payloadBatch;\n    var snapToValue = payloadInfo.snapToValue;\n\n    // Fill content of event obj for echarts.connect.\n    // By defualt use the first involved series data as a sample to connect.\n    if (payloadBatch[0] && outputFinder.seriesIndex == null) {\n        extend(outputFinder, payloadBatch[0]);\n    }\n\n    // If no linkSource input, this process is for collecting link\n    // target, where snap should not be accepted.\n    if (!dontSnap && axisInfo.snap) {\n        if (axis.containData(snapToValue) && snapToValue != null) {\n            newValue = snapToValue;\n        }\n    }\n\n    updaters.showPointer(axisInfo, newValue, payloadBatch, outputFinder);\n    // Tooltip should always be snapToValue, otherwise there will be\n    // incorrect \"axis value ~ series value\" mapping displayed in tooltip.\n    updaters.showTooltip(axisInfo, payloadInfo, snapToValue);\n}\n\nfunction buildPayloadsBySeries(value, axisInfo) {\n    var axis = axisInfo.axis;\n    var dim = axis.dim;\n    var snapToValue = value;\n    var payloadBatch = [];\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n\n    each$14(axisInfo.seriesModels, function (series, idx) {\n        var dataDim = series.getData().mapDimension(dim, true);\n        var seriesNestestValue;\n        var dataIndices;\n\n        if (series.getAxisTooltipData) {\n            var result = series.getAxisTooltipData(dataDim, value, axis);\n            dataIndices = result.dataIndices;\n            seriesNestestValue = result.nestestValue;\n        }\n        else {\n            dataIndices = series.getData().indicesOfNearest(\n                dataDim[0],\n                value,\n                // Add a threshold to avoid find the wrong dataIndex\n                // when data length is not same.\n                // false,\n                axis.type === 'category' ? 0.5 : null\n            );\n            if (!dataIndices.length) {\n                return;\n            }\n            seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]);\n        }\n\n        if (seriesNestestValue == null || !isFinite(seriesNestestValue)) {\n            return;\n        }\n\n        var diff = value - seriesNestestValue;\n        var dist = Math.abs(diff);\n        // Consider category case\n        if (dist <= minDist) {\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                snapToValue = seriesNestestValue;\n                payloadBatch.length = 0;\n            }\n            each$14(dataIndices, function (dataIndex) {\n                payloadBatch.push({\n                    seriesIndex: series.seriesIndex,\n                    dataIndexInside: dataIndex,\n                    dataIndex: series.getData().getRawIndex(dataIndex)\n                });\n            });\n        }\n    });\n\n    return {\n        payloadBatch: payloadBatch,\n        snapToValue: snapToValue\n    };\n}\n\nfunction showPointer(showValueMap, axisInfo, value, payloadBatch) {\n    showValueMap[axisInfo.key] = {value: value, payloadBatch: payloadBatch};\n}\n\nfunction showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) {\n    var payloadBatch = payloadInfo.payloadBatch;\n    var axis = axisInfo.axis;\n    var axisModel = axis.model;\n    var axisPointerModel = axisInfo.axisPointerModel;\n\n    // If no data, do not create anything in dataByCoordSys,\n    // whose length will be used to judge whether dispatch action.\n    if (!axisInfo.triggerTooltip || !payloadBatch.length) {\n        return;\n    }\n\n    var coordSysModel = axisInfo.coordSys.model;\n    var coordSysKey = makeKey(coordSysModel);\n    var coordSysItem = dataByCoordSys.map[coordSysKey];\n    if (!coordSysItem) {\n        coordSysItem = dataByCoordSys.map[coordSysKey] = {\n            coordSysId: coordSysModel.id,\n            coordSysIndex: coordSysModel.componentIndex,\n            coordSysType: coordSysModel.type,\n            coordSysMainType: coordSysModel.mainType,\n            dataByAxis: []\n        };\n        dataByCoordSys.list.push(coordSysItem);\n    }\n\n    coordSysItem.dataByAxis.push({\n        axisDim: axis.dim,\n        axisIndex: axisModel.componentIndex,\n        axisType: axisModel.type,\n        axisId: axisModel.id,\n        value: value,\n        // Caustion: viewHelper.getValueLabel is actually on \"view stage\", which\n        // depends that all models have been updated. So it should not be performed\n        // here. Considering axisPointerModel used here is volatile, which is hard\n        // to be retrieve in TooltipView, we prepare parameters here.\n        valueLabelOpt: {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        },\n        seriesDataIndices: payloadBatch.slice()\n    });\n}\n\nfunction updateModelActually(showValueMap, axesInfo, outputFinder) {\n    var outputAxesInfo = outputFinder.axesInfo = [];\n    // Basic logic: If no 'show' required, 'hide' this axisPointer.\n    each$14(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        var valItem = showValueMap[key];\n\n        if (valItem) {\n            !axisInfo.useHandle && (option.status = 'show');\n            option.value = valItem.value;\n            // For label formatter param and highlight.\n            option.seriesDataIndices = (valItem.payloadBatch || []).slice();\n        }\n        // When always show (e.g., handle used), remain\n        // original value and status.\n        else {\n            // If hide, value still need to be set, consider\n            // click legend to toggle axis blank.\n            !axisInfo.useHandle && (option.status = 'hide');\n        }\n\n        // If status is 'hide', should be no info in payload.\n        option.status === 'show' && outputAxesInfo.push({\n            axisDim: axisInfo.axis.dim,\n            axisIndex: axisInfo.axis.model.componentIndex,\n            value: option.value\n        });\n    });\n}\n\nfunction dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) {\n    // Basic logic: If no showTip required, hideTip will be dispatched.\n    if (illegalPoint(point) || !dataByCoordSys.list.length) {\n        dispatchAction({type: 'hideTip'});\n        return;\n    }\n\n    // In most case only one axis (or event one series is used). It is\n    // convinient to fetch payload.seriesIndex and payload.dataIndex\n    // dirtectly. So put the first seriesIndex and dataIndex of the first\n    // axis on the payload.\n    var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {};\n\n    dispatchAction({\n        type: 'showTip',\n        escapeConnect: true,\n        x: point[0],\n        y: point[1],\n        tooltipOption: payload.tooltipOption,\n        position: payload.position,\n        dataIndexInside: sampleItem.dataIndexInside,\n        dataIndex: sampleItem.dataIndex,\n        seriesIndex: sampleItem.seriesIndex,\n        dataByCoordSys: dataByCoordSys.list\n    });\n}\n\nfunction dispatchHighDownActually(axesInfo, dispatchAction, api) {\n    // FIXME\n    // highlight status modification shoule be a stage of main process?\n    // (Consider confilct (e.g., legend and axisPointer) and setOption)\n\n    var zr = api.getZr();\n    var highDownKey = 'axisPointerLastHighlights';\n    var lastHighlights = inner$9(zr)[highDownKey] || {};\n    var newHighlights = inner$9(zr)[highDownKey] = {};\n\n    // Update highlight/downplay status according to axisPointer model.\n    // Build hash map and remove duplicate incidentally.\n    each$14(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        option.status === 'show' && each$14(option.seriesDataIndices, function (batchItem) {\n            var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex;\n            newHighlights[key] = batchItem;\n        });\n    });\n\n    // Diff.\n    var toHighlight = [];\n    var toDownplay = [];\n    each$1(lastHighlights, function (batchItem, key) {\n        !newHighlights[key] && toDownplay.push(batchItem);\n    });\n    each$1(newHighlights, function (batchItem, key) {\n        !lastHighlights[key] && toHighlight.push(batchItem);\n    });\n\n    toDownplay.length && api.dispatchAction({\n        type: 'downplay', escapeConnect: true, batch: toDownplay\n    });\n    toHighlight.length && api.dispatchAction({\n        type: 'highlight', escapeConnect: true, batch: toHighlight\n    });\n}\n\nfunction findInputAxisInfo(inputAxesInfo, axisInfo) {\n    for (var i = 0; i < (inputAxesInfo || []).length; i++) {\n        var inputAxisInfo = inputAxesInfo[i];\n        if (axisInfo.axis.dim === inputAxisInfo.axisDim\n            && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex\n        ) {\n            return inputAxisInfo;\n        }\n    }\n}\n\nfunction makeMapperParam(axisInfo) {\n    var axisModel = axisInfo.axis.model;\n    var item = {};\n    var dim = item.axisDim = axisInfo.axis.dim;\n    item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex;\n    item.axisName = item[dim + 'AxisName'] = axisModel.name;\n    item.axisId = item[dim + 'AxisId'] = axisModel.id;\n    return item;\n}\n\nfunction illegalPoint(point) {\n    return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerModel = extendComponentModel({\n\n    type: 'axisPointer',\n\n    coordSysAxesInfo: null,\n\n    defaultOption: {\n        // 'auto' means that show when triggered by tooltip or handle.\n        show: 'auto',\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: null, // set default in AxisPonterView.js\n\n        zlevel: 0,\n        z: 50,\n\n        type: 'line', // 'line' 'shadow' 'cross' 'none'.\n        // axispointer triggered by tootip determine snap automatically,\n        // see `modelHelper`.\n        snap: false,\n        triggerTooltip: true,\n\n        value: null,\n        status: null, // Init value depends on whether handle is used.\n\n        // [group0, group1, ...]\n        // Each group can be: {\n        //      mapper: function () {},\n        //      singleTooltip: 'multiple',  // 'multiple' or 'single'\n        //      xAxisId: ...,\n        //      yAxisName: ...,\n        //      angleAxisIndex: ...\n        // }\n        // mapper: can be ignored.\n        //      input: {axisInfo, value}\n        //      output: {axisInfo, value}\n        link: [],\n\n        // Do not set 'auto' here, otherwise global animation: false\n        // will not effect at this axispointer.\n        animation: null,\n        animationDurationUpdate: 200,\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            type: 'solid'\n        },\n\n        shadowStyle: {\n            color: 'rgba(150,150,150,0.3)'\n        },\n\n        label: {\n            show: true,\n            formatter: null, // string | Function\n            precision: 'auto', // Or a number like 0, 1, 2 ...\n            margin: 3,\n            color: '#fff',\n            padding: [5, 7, 5, 7],\n            backgroundColor: 'auto', // default: axis line color\n            borderColor: null,\n            borderWidth: 0,\n            shadowBlur: 3,\n            shadowColor: '#aaa'\n            // Considering applicability, common style should\n            // better not have shadowOffset.\n            // shadowOffsetX: 0,\n            // shadowOffsetY: 2\n        },\n\n        handle: {\n            show: false,\n            /* eslint-disable */\n            icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line\n            /* eslint-enable */\n            size: 45,\n            // handle margin is from symbol center to axis, which is stable when circular move.\n            margin: 50,\n            // color: '#1b8bbd'\n            // color: '#2f4554'\n            color: '#333',\n            shadowBlur: 3,\n            shadowColor: '#aaa',\n            shadowOffsetX: 0,\n            shadowOffsetY: 2,\n\n            // For mobile performance\n            throttle: 40\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$10 = makeInner();\nvar each$15 = each$1;\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n * @param {Function} handler\n *      param: {string} currTrigger\n *      param: {Array.<number>} point\n */\nfunction register(key, api, handler) {\n    if (env$1.node) {\n        return;\n    }\n\n    var zr = api.getZr();\n    inner$10(zr).records || (inner$10(zr).records = {});\n\n    initGlobalListeners(zr, api);\n\n    var record = inner$10(zr).records[key] || (inner$10(zr).records[key] = {});\n    record.handler = handler;\n}\n\nfunction initGlobalListeners(zr, api) {\n    if (inner$10(zr).initialized) {\n        return;\n    }\n\n    inner$10(zr).initialized = true;\n\n    useHandler('click', curry(doEnter, 'click'));\n    useHandler('mousemove', curry(doEnter, 'mousemove'));\n    // useHandler('mouseout', onLeave);\n    useHandler('globalout', onLeave);\n\n    function useHandler(eventType, cb) {\n        zr.on(eventType, function (e) {\n            var dis = makeDispatchAction(api);\n\n            each$15(inner$10(zr).records, function (record) {\n                record && cb(record, e, dis.dispatchAction);\n            });\n\n            dispatchTooltipFinally(dis.pendings, api);\n        });\n    }\n}\n\nfunction dispatchTooltipFinally(pendings, api) {\n    var showLen = pendings.showTip.length;\n    var hideLen = pendings.hideTip.length;\n\n    var actuallyPayload;\n    if (showLen) {\n        actuallyPayload = pendings.showTip[showLen - 1];\n    }\n    else if (hideLen) {\n        actuallyPayload = pendings.hideTip[hideLen - 1];\n    }\n    if (actuallyPayload) {\n        actuallyPayload.dispatchAction = null;\n        api.dispatchAction(actuallyPayload);\n    }\n}\n\nfunction onLeave(record, e, dispatchAction) {\n    record.handler('leave', null, dispatchAction);\n}\n\nfunction doEnter(currTrigger, record, e, dispatchAction) {\n    record.handler(currTrigger, e, dispatchAction);\n}\n\nfunction makeDispatchAction(api) {\n    var pendings = {\n        showTip: [],\n        hideTip: []\n    };\n    // FIXME\n    // better approach?\n    // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip,\n    // which may be conflict, (axisPointer call showTip but tooltip call hideTip);\n    // So we have to add \"final stage\" to merge those dispatched actions.\n    var dispatchAction = function (payload) {\n        var pendingList = pendings[payload.type];\n        if (pendingList) {\n            pendingList.push(payload);\n        }\n        else {\n            payload.dispatchAction = dispatchAction;\n            api.dispatchAction(payload);\n        }\n    };\n\n    return {\n        dispatchAction: dispatchAction,\n        pendings: pendings\n    };\n}\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction unregister(key, api) {\n    if (env$1.node) {\n        return;\n    }\n    var zr = api.getZr();\n    var record = (inner$10(zr).records || {})[key];\n    if (record) {\n        inner$10(zr).records[key] = null;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerView = extendComponentView({\n\n    type: 'axisPointer',\n\n    render: function (globalAxisPointerModel, ecModel, api) {\n        var globalTooltipModel = ecModel.getComponent('tooltip');\n        var triggerOn = globalAxisPointerModel.get('triggerOn')\n            || (globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click');\n\n        // Register global listener in AxisPointerView to enable\n        // AxisPointerView to be independent to Tooltip.\n        register(\n            'axisPointer',\n            api,\n            function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none'\n                    && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)\n                ) {\n                    dispatchAction({\n                        type: 'updateAxisPointer',\n                        currTrigger: currTrigger,\n                        x: e && e.offsetX,\n                        y: e && e.offsetY\n                    });\n                }\n            }\n        );\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        unregister(api.getZr(), 'axisPointer');\n        AxisPointerView.superApply(this._model, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        unregister('axisPointer', api);\n        AxisPointerView.superApply(this._model, 'dispose', arguments);\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$11 = makeInner();\nvar clone$4 = clone;\nvar bind$2 = bind;\n\n/**\n * Base axis pointer class in 2D.\n * Implemenents {module:echarts/component/axis/IAxisPointer}.\n */\nfunction BaseAxisPointer() {\n}\n\nBaseAxisPointer.prototype = {\n\n    /**\n     * @private\n     */\n    _group: null,\n\n    /**\n     * @private\n     */\n    _lastGraphicKey: null,\n\n    /**\n     * @private\n     */\n    _handle: null,\n\n    /**\n     * @private\n     */\n    _dragging: false,\n\n    /**\n     * @private\n     */\n    _lastValue: null,\n\n    /**\n     * @private\n     */\n    _lastStatus: null,\n\n    /**\n     * @private\n     */\n    _payloadInfo: null,\n\n    /**\n     * In px, arbitrary value. Do not set too small,\n     * no animation is ok for most cases.\n     * @protected\n     */\n    animationThreshold: 15,\n\n    /**\n     * @implement\n     */\n    render: function (axisModel, axisPointerModel, api, forceRender) {\n        var value = axisPointerModel.get('value');\n        var status = axisPointerModel.get('status');\n\n        // Bind them to `this`, not in closure, otherwise they will not\n        // be replaced when user calling setOption in not merge mode.\n        this._axisModel = axisModel;\n        this._axisPointerModel = axisPointerModel;\n        this._api = api;\n\n        // Optimize: `render` will be called repeatly during mouse move.\n        // So it is power consuming if performing `render` each time,\n        // especially on mobile device.\n        if (!forceRender\n            && this._lastValue === value\n            && this._lastStatus === status\n        ) {\n            return;\n        }\n        this._lastValue = value;\n        this._lastStatus = status;\n\n        var group = this._group;\n        var handle = this._handle;\n\n        if (!status || status === 'hide') {\n            // Do not clear here, for animation better.\n            group && group.hide();\n            handle && handle.hide();\n            return;\n        }\n        group && group.show();\n        handle && handle.show();\n\n        // Otherwise status is 'show'\n        var elOption = {};\n        this.makeElOption(elOption, value, axisModel, axisPointerModel, api);\n\n        // Enable change axis pointer type.\n        var graphicKey = elOption.graphicKey;\n        if (graphicKey !== this._lastGraphicKey) {\n            this.clear(api);\n        }\n        this._lastGraphicKey = graphicKey;\n\n        var moveAnimation = this._moveAnimation\n            = this.determineAnimation(axisModel, axisPointerModel);\n\n        if (!group) {\n            group = this._group = new Group();\n            this.createPointerEl(group, elOption, axisModel, axisPointerModel);\n            this.createLabelEl(group, elOption, axisModel, axisPointerModel);\n            api.getZr().add(group);\n        }\n        else {\n            var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation);\n            this.updatePointerEl(group, elOption, doUpdateProps, axisPointerModel);\n            this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);\n        }\n\n        updateMandatoryProps(group, axisPointerModel, true);\n\n        this._renderHandle(value);\n    },\n\n    /**\n     * @implement\n     */\n    remove: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @implement\n     */\n    dispose: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @protected\n     */\n    determineAnimation: function (axisModel, axisPointerModel) {\n        var animation = axisPointerModel.get('animation');\n        var axis = axisModel.axis;\n        var isCategoryAxis = axis.type === 'category';\n        var useSnap = axisPointerModel.get('snap');\n\n        // Value axis without snap always do not snap.\n        if (!useSnap && !isCategoryAxis) {\n            return false;\n        }\n\n        if (animation === 'auto' || animation == null) {\n            var animationThreshold = this.animationThreshold;\n            if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {\n                return true;\n            }\n\n            // It is important to auto animation when snap used. Consider if there is\n            // a dataZoom, animation will be disabled when too many points exist, while\n            // it will be enabled for better visual effect when little points exist.\n            if (useSnap) {\n                var seriesDataCount = getAxisInfo(axisModel).seriesDataCount;\n                var axisExtent = axis.getExtent();\n                // Approximate band width\n                return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;\n            }\n\n            return false;\n        }\n\n        return animation === true;\n    },\n\n    /**\n     * add {pointer, label, graphicKey} to elOption\n     * @protected\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        // Shoule be implemenented by sub-class.\n    },\n\n    /**\n     * @protected\n     */\n    createPointerEl: function (group, elOption, axisModel, axisPointerModel) {\n        var pointerOption = elOption.pointer;\n        if (pointerOption) {\n            var pointerEl = inner$11(group).pointerEl = new graphic[pointerOption.type](\n                clone$4(elOption.pointer)\n            );\n            group.add(pointerEl);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    createLabelEl: function (group, elOption, axisModel, axisPointerModel) {\n        if (elOption.label) {\n            var labelEl = inner$11(group).labelEl = new Rect(\n                clone$4(elOption.label)\n            );\n\n            group.add(labelEl);\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updatePointerEl: function (group, elOption, updateProps$$1) {\n        var pointerEl = inner$11(group).pointerEl;\n        if (pointerEl) {\n            pointerEl.setStyle(elOption.pointer.style);\n            updateProps$$1(pointerEl, {shape: elOption.pointer.shape});\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updateLabelEl: function (group, elOption, updateProps$$1, axisPointerModel) {\n        var labelEl = inner$11(group).labelEl;\n        if (labelEl) {\n            labelEl.setStyle(elOption.label.style);\n            updateProps$$1(labelEl, {\n                // Consider text length change in vertical axis, animation should\n                // be used on shape, otherwise the effect will be weird.\n                shape: elOption.label.shape,\n                position: elOption.label.position\n            });\n\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderHandle: function (value) {\n        if (this._dragging || !this.updateHandleTransform) {\n            return;\n        }\n\n        var axisPointerModel = this._axisPointerModel;\n        var zr = this._api.getZr();\n        var handle = this._handle;\n        var handleModel = axisPointerModel.getModel('handle');\n\n        var status = axisPointerModel.get('status');\n        if (!handleModel.get('show') || !status || status === 'hide') {\n            handle && zr.remove(handle);\n            this._handle = null;\n            return;\n        }\n\n        var isInit;\n        if (!this._handle) {\n            isInit = true;\n            handle = this._handle = createIcon(\n                handleModel.get('icon'),\n                {\n                    cursor: 'move',\n                    draggable: true,\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    onmousedown: bind$2(this._onHandleDragMove, this, 0, 0),\n                    drift: bind$2(this._onHandleDragMove, this),\n                    ondragend: bind$2(this._onHandleDragEnd, this)\n                }\n            );\n            zr.add(handle);\n        }\n\n        updateMandatoryProps(handle, axisPointerModel, false);\n\n        // update style\n        var includeStyles = [\n            'color', 'borderColor', 'borderWidth', 'opacity',\n            'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'\n        ];\n        handle.setStyle(handleModel.getItemStyle(null, includeStyles));\n\n        // update position\n        var handleSize = handleModel.get('size');\n        if (!isArray(handleSize)) {\n            handleSize = [handleSize, handleSize];\n        }\n        handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]);\n\n        createOrUpdate(\n            this,\n            '_doDispatchAxisPointer',\n            handleModel.get('throttle') || 0,\n            'fixRate'\n        );\n\n        this._moveHandleToValue(value, isInit);\n    },\n\n    /**\n     * @private\n     */\n    _moveHandleToValue: function (value, isInit) {\n        updateProps$1(\n            this._axisPointerModel,\n            !isInit && this._moveAnimation,\n            this._handle,\n            getHandleTransProps(this.getHandleTransform(\n                value, this._axisModel, this._axisPointerModel\n            ))\n        );\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragMove: function (dx, dy) {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        this._dragging = true;\n\n        // Persistent for throttle.\n        var trans = this.updateHandleTransform(\n            getHandleTransProps(handle),\n            [dx, dy],\n            this._axisModel,\n            this._axisPointerModel\n        );\n        this._payloadInfo = trans;\n\n        handle.stopAnimation();\n        handle.attr(getHandleTransProps(trans));\n        inner$11(handle).lastProp = null;\n\n        this._doDispatchAxisPointer();\n    },\n\n    /**\n     * Throttled method.\n     * @private\n     */\n    _doDispatchAxisPointer: function () {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var payloadInfo = this._payloadInfo;\n        var axisModel = this._axisModel;\n        this._api.dispatchAction({\n            type: 'updateAxisPointer',\n            x: payloadInfo.cursorPoint[0],\n            y: payloadInfo.cursorPoint[1],\n            tooltipOption: payloadInfo.tooltipOption,\n            axesInfo: [{\n                axisDim: axisModel.axis.dim,\n                axisIndex: axisModel.componentIndex\n            }]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragEnd: function (moveAnimation) {\n        this._dragging = false;\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var value = this._axisPointerModel.get('value');\n        // Consider snap or categroy axis, handle may be not consistent with\n        // axisPointer. So move handle to align the exact value position when\n        // drag ended.\n        this._moveHandleToValue(value);\n\n        // For the effect: tooltip will be shown when finger holding on handle\n        // button, and will be hidden after finger left handle button.\n        this._api.dispatchAction({\n            type: 'hideTip'\n        });\n    },\n\n    /**\n     * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {number} value\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0}\n     */\n    getHandleTransform: null,\n\n    /**\n     * * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {Object} transform {position, rotation}\n     * @param {Array.<number>} delta [dx, dy]\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]}\n     */\n    updateHandleTransform: null,\n\n    /**\n     * @private\n     */\n    clear: function (api) {\n        this._lastValue = null;\n        this._lastStatus = null;\n\n        var zr = api.getZr();\n        var group = this._group;\n        var handle = this._handle;\n        if (zr && group) {\n            this._lastGraphicKey = null;\n            group && zr.remove(group);\n            handle && zr.remove(handle);\n            this._group = null;\n            this._handle = null;\n            this._payloadInfo = null;\n        }\n    },\n\n    /**\n     * @protected\n     */\n    doClear: function () {\n        // Implemented by sub-class if necessary.\n    },\n\n    /**\n     * @protected\n     * @param {Array.<number>} xy\n     * @param {Array.<number>} wh\n     * @param {number} [xDimIndex=0] or 1\n     */\n    buildLabel: function (xy, wh, xDimIndex) {\n        xDimIndex = xDimIndex || 0;\n        return {\n            x: xy[xDimIndex],\n            y: xy[1 - xDimIndex],\n            width: wh[xDimIndex],\n            height: wh[1 - xDimIndex]\n        };\n    }\n};\n\nBaseAxisPointer.prototype.constructor = BaseAxisPointer;\n\n\nfunction updateProps$1(animationModel, moveAnimation, el, props) {\n    // Animation optimize.\n    if (!propsEqual(inner$11(el).lastProp, props)) {\n        inner$11(el).lastProp = props;\n        moveAnimation\n            ? updateProps(el, props, animationModel)\n            : (el.stopAnimation(), el.attr(props));\n    }\n}\n\nfunction propsEqual(lastProps, newProps) {\n    if (isObject$1(lastProps) && isObject$1(newProps)) {\n        var equals = true;\n        each$1(newProps, function (item, key) {\n            equals = equals && propsEqual(lastProps[key], item);\n        });\n        return !!equals;\n    }\n    else {\n        return lastProps === newProps;\n    }\n}\n\nfunction updateLabelShowHide(labelEl, axisPointerModel) {\n    labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide']();\n}\n\nfunction getHandleTransProps(trans) {\n    return {\n        position: trans.position.slice(),\n        rotation: trans.rotation || 0\n    };\n}\n\nfunction updateMandatoryProps(group, axisPointerModel, silent) {\n    var z = axisPointerModel.get('z');\n    var zlevel = axisPointerModel.get('zlevel');\n\n    group && group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n            el.silent = silent;\n        }\n    });\n}\n\nenableClassExtend(BaseAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Model} axisPointerModel\n */\nfunction buildElStyle(axisPointerModel) {\n    var axisPointerType = axisPointerModel.get('type');\n    var styleModel = axisPointerModel.getModel(axisPointerType + 'Style');\n    var style;\n    if (axisPointerType === 'line') {\n        style = styleModel.getLineStyle();\n        style.fill = null;\n    }\n    else if (axisPointerType === 'shadow') {\n        style = styleModel.getAreaStyle();\n        style.stroke = null;\n    }\n    return style;\n}\n\n/**\n * @param {Function} labelPos {align, verticalAlign, position}\n */\nfunction buildLabelElOption(\n    elOption, axisModel, axisPointerModel, api, labelPos\n) {\n    var value = axisPointerModel.get('value');\n    var text = getValueLabel(\n        value, axisModel.axis, axisModel.ecModel,\n        axisPointerModel.get('seriesDataIndices'),\n        {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        }\n    );\n    var labelModel = axisPointerModel.getModel('label');\n    var paddings = normalizeCssArray$1(labelModel.get('padding') || 0);\n\n    var font = labelModel.getFont();\n    var textRect = getBoundingRect(text, font);\n\n    var position = labelPos.position;\n    var width = textRect.width + paddings[1] + paddings[3];\n    var height = textRect.height + paddings[0] + paddings[2];\n\n    // Adjust by align.\n    var align = labelPos.align;\n    align === 'right' && (position[0] -= width);\n    align === 'center' && (position[0] -= width / 2);\n    var verticalAlign = labelPos.verticalAlign;\n    verticalAlign === 'bottom' && (position[1] -= height);\n    verticalAlign === 'middle' && (position[1] -= height / 2);\n\n    // Not overflow ec container\n    confineInContainer(position, width, height, api);\n\n    var bgColor = labelModel.get('backgroundColor');\n    if (!bgColor || bgColor === 'auto') {\n        bgColor = axisModel.get('axisLine.lineStyle.color');\n    }\n\n    elOption.label = {\n        shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')},\n        position: position.slice(),\n        // TODO: rich\n        style: {\n            text: text,\n            textFont: font,\n            textFill: labelModel.getTextColor(),\n            textPosition: 'inside',\n            fill: bgColor,\n            stroke: labelModel.get('borderColor') || 'transparent',\n            lineWidth: labelModel.get('borderWidth') || 0,\n            shadowBlur: labelModel.get('shadowBlur'),\n            shadowColor: labelModel.get('shadowColor'),\n            shadowOffsetX: labelModel.get('shadowOffsetX'),\n            shadowOffsetY: labelModel.get('shadowOffsetY')\n        },\n        // Lable should be over axisPointer.\n        z2: 10\n    };\n}\n\n// Do not overflow ec container\nfunction confineInContainer(position, width, height, api) {\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    position[0] = Math.min(position[0] + width, viewWidth) - width;\n    position[1] = Math.min(position[1] + height, viewHeight) - height;\n    position[0] = Math.max(position[0], 0);\n    position[1] = Math.max(position[1], 0);\n}\n\n/**\n * @param {number} value\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} opt\n * @param {Array.<Object>} seriesDataIndices\n * @param {number|string} opt.precision 'auto' or a number\n * @param {string|Function} opt.formatter label formatter\n */\nfunction getValueLabel(value, axis, ecModel, seriesDataIndices, opt) {\n    value = axis.scale.parse(value);\n    var text = axis.scale.getLabel(\n        // If `precision` is set, width can be fixed (like '12.00500'), which\n        // helps to debounce when when moving label.\n        value, {precision: opt.precision}\n    );\n    var formatter = opt.formatter;\n\n    if (formatter) {\n        var params = {\n            value: getAxisRawValue(axis, value),\n            seriesData: []\n        };\n        each$1(seriesDataIndices, function (idxItem) {\n            var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n            var dataIndex = idxItem.dataIndexInside;\n            var dataParams = series && series.getDataParams(dataIndex);\n            dataParams && params.seriesData.push(dataParams);\n        });\n\n        if (isString(formatter)) {\n            text = formatter.replace('{value}', text);\n        }\n        else if (isFunction$1(formatter)) {\n            text = formatter(params);\n        }\n    }\n\n    return text;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @param {number} value\n * @param {Object} layoutInfo {\n *  rotation, position, labelOffset, labelDirection, labelMargin\n * }\n */\nfunction getTransformedPosition(axis, value, layoutInfo) {\n    var transform = create$1();\n    rotate(transform, transform, layoutInfo.rotation);\n    translate(transform, transform, layoutInfo.position);\n\n    return applyTransform$1([\n        axis.dataToCoord(value),\n        (layoutInfo.labelOffset || 0)\n            + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)\n    ], transform);\n}\n\nfunction buildCartesianSingleLabelElOption(\n    value, elOption, layoutInfo, axisModel, axisPointerModel, api\n) {\n    var textLayout = AxisBuilder.innerTextLayout(\n        layoutInfo.rotation, 0, layoutInfo.labelDirection\n    );\n    layoutInfo.labelMargin = axisPointerModel.get('label.margin');\n    buildLabelElOption(elOption, axisModel, axisPointerModel, api, {\n        position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n        align: textLayout.textAlign,\n        verticalAlign: textLayout.textVerticalAlign\n    });\n}\n\n/**\n * @param {Array.<number>} p1\n * @param {Array.<number>} p2\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeLineShape(p1, p2, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x1: p1[xDimIndex],\n        y1: p1[1 - xDimIndex],\n        x2: p2[xDimIndex],\n        y2: p2[1 - xDimIndex]\n    };\n}\n\n/**\n * @param {Array.<number>} xy\n * @param {Array.<number>} wh\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeRectShape(xy, wh, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x: xy[xDimIndex],\n        y: xy[1 - xDimIndex],\n        width: wh[xDimIndex],\n        height: wh[1 - xDimIndex]\n    };\n}\n\nfunction makeSectorShape(cx, cy, r0, r, startAngle, endAngle) {\n    return {\n        cx: cx,\n        cy: cy,\n        r0: r0,\n        r: r,\n        startAngle: startAngle,\n        endAngle: endAngle,\n        clockwise: true\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CartesianAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisPointerType = axisPointerModel.get('type');\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true));\n\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$1(grid.model, axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, {\n            labelInside: false\n        });\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisExtent = axis.getGlobalExtent(true);\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var dimIndex = axis.dim === 'x' ? 0 : 1;\n\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        // Make tooltip do not overlap axisPointer and in the middle of the grid.\n        var tooltipOptions = [{verticalAlign: 'middle'}, {align: 'center'}];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: tooltipOptions[dimIndex]\n        };\n    }\n\n});\n\nfunction getCartesian(grid, axis) {\n    var opt = {};\n    opt[axis.dim + 'AxisIndex'] = axis.index;\n    return grid.getCartesian(opt);\n}\n\nvar pointerShapeBuilder = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getAxisDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getAxisDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getAxisDimIndex(axis) {\n    return axis.dim === 'x' ? 0 : 1;\n}\n\nAxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// CartesianAxisPointer is not supposed to be required here. But consider\n// echarts.simple.js and online build tooltip, which only require gridSimple,\n// CartesianAxisPointer should be able to required somewhere.\nregisterPreprocessor(function (option) {\n    // Always has a global axisPointerModel for default setting.\n    if (option) {\n        (!option.axisPointer || option.axisPointer.length === 0)\n            && (option.axisPointer = {});\n\n        var link = option.axisPointer.link;\n        // Normalize to array to avoid object mergin. But if link\n        // is not set, remain null/undefined, otherwise it will\n        // override existent link setting.\n        if (link && !isArray(link)) {\n            option.axisPointer.link = [link];\n        }\n    }\n});\n\n// This process should proformed after coordinate systems created\n// and series data processed. So put it on statistic processing stage.\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) {\n    // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n    // allAxesInfo should be updated when setOption performed.\n    ecModel.getComponent('axisPointer').coordSysAxesInfo\n        = collect(ecModel, api);\n});\n\n// Broadcast to all views.\nregisterAction({\n    type: 'updateAxisPointer',\n    event: 'updateAxisPointer',\n    update: ':updateAxisPointer'\n}, axisTrigger);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar XY = ['x', 'y'];\nvar WH = ['width', 'height'];\n\nvar SingleAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var coordSys = axis.coordinateSystem;\n        var otherExtent = getGlobalExtent(coordSys, 1 - getPointDimIndex(axis));\n        var pixelValue = coordSys.dataToPoint(value)[0];\n\n        var axisPointerType = axisPointerModel.get('type');\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder$1[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$2(axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$2(axisModel, {labelInside: false});\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var coordSys = axis.coordinateSystem;\n        var dimIndex = getPointDimIndex(axis);\n        var axisExtent = getGlobalExtent(coordSys, dimIndex);\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n        var otherExtent = getGlobalExtent(coordSys, 1 - dimIndex);\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: {\n                verticalAlign: 'middle'\n            }\n        };\n    }\n});\n\nvar pointerShapeBuilder$1 = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getPointDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = axis.getBandWidth();\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getPointDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getPointDimIndex(axis) {\n    return axis.isHorizontal() ? 0 : 1;\n}\n\nfunction getGlobalExtent(coordSys, dimIndex) {\n    var rect = coordSys.getRect();\n    return [rect[XY[dimIndex]], rect[XY[dimIndex]] + rect[WH[dimIndex]]];\n}\n\nAxisView.registerAxisPointerClass('SingleAxisPointer', SingleAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n    type: 'single'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  Define the themeRiver view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar DATA_NAME_INDEX = 2;\n\nvar ThemeRiverSeries = SeriesModel.extend({\n\n    type: 'series.themeRiver',\n\n    dependencies: ['singleAxis'],\n\n    /**\n     * @readOnly\n     * @type {module:zrender/core/util#HashMap}\n     */\n    nameMap: null,\n\n    /**\n     * @override\n     */\n    init: function (option) {\n        // eslint-disable-next-line\n        ThemeRiverSeries.superApply(this, 'init', arguments);\n\n        // Put this function here is for the sake of consistency of code style.\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n    },\n\n    /**\n     * If there is no value of a certain point in the time for some event,set it value to 0.\n     *\n     * @param {Array} data  initial data in the option\n     * @return {Array}\n     */\n    fixData: function (data) {\n        var rawDataLength = data.length;\n\n        // grouped data by name\n        var dataByName = nest()\n            .key(function (dataItem) {\n                return dataItem[2];\n            })\n            .entries(data);\n\n        // data group in each layer\n        var layData = map(dataByName, function (d) {\n            return {\n                name: d.key,\n                dataList: d.values\n            };\n        });\n\n        var layerNum = layData.length;\n        var largestLayer = -1;\n        var index = -1;\n        for (var i = 0; i < layerNum; ++i) {\n            var len = layData[i].dataList.length;\n            if (len > largestLayer) {\n                largestLayer = len;\n                index = i;\n            }\n        }\n\n        for (var k = 0; k < layerNum; ++k) {\n            if (k === index) {\n                continue;\n            }\n            var name = layData[k].name;\n            for (var j = 0; j < largestLayer; ++j) {\n                var timeValue = layData[index].dataList[j][0];\n                var length = layData[k].dataList.length;\n                var keyIndex = -1;\n                for (var l = 0; l < length; ++l) {\n                    var value = layData[k].dataList[l][0];\n                    if (value === timeValue) {\n                        keyIndex = l;\n                        break;\n                    }\n                }\n                if (keyIndex === -1) {\n                    data[rawDataLength] = [];\n                    data[rawDataLength][0] = timeValue;\n                    data[rawDataLength][1] = 0;\n                    data[rawDataLength][2] = name;\n                    rawDataLength++;\n\n                }\n            }\n        }\n        return data;\n    },\n\n    /**\n     * @override\n     * @param  {Object} option  the initial option that user gived\n     * @param  {module:echarts/model/Model} ecModel  the model object for themeRiver option\n     * @return {module:echarts/data/List}\n     */\n    getInitialData: function (option, ecModel) {\n\n        var singleAxisModel = ecModel.queryComponents({\n            mainType: 'singleAxis',\n            index: this.get('singleAxisIndex'),\n            id: this.get('singleAxisId')\n        })[0];\n\n        var axisType = singleAxisModel.get('type');\n\n        // filter the data item with the value of label is undefined\n        var filterData = filter(option.data, function (dataItem) {\n            return dataItem[2] !== undefined;\n        });\n\n        // ??? TODO design a stage to transfer data for themeRiver and lines?\n        var data = this.fixData(filterData || []);\n        var nameList = [];\n        var nameMap = this.nameMap = createHashMap();\n        var count = 0;\n\n        for (var i = 0; i < data.length; ++i) {\n            nameList.push(data[i][DATA_NAME_INDEX]);\n            if (!nameMap.get(data[i][DATA_NAME_INDEX])) {\n                nameMap.set(data[i][DATA_NAME_INDEX], count);\n                count++;\n            }\n        }\n\n        var dimensionsInfo = createDimensions(data, {\n            coordDimensions: ['single'],\n            dimensionsDefine: [\n                {\n                    name: 'time',\n                    type: getDimensionTypeByAxis(axisType)\n                },\n                {\n                    name: 'value',\n                    type: 'float'\n                },\n                {\n                    name: 'name',\n                    type: 'ordinal'\n                }\n            ],\n            encodeDefine: {\n                single: 0,\n                value: 1,\n                itemName: 2\n            }\n        });\n\n        var list = new List(dimensionsInfo, this);\n        list.initData(data);\n\n        return list;\n    },\n\n    /**\n     * The raw data is divided into multiple layers and each layer\n     *     has same name.\n     *\n     * @return {Array.<Array.<number>>}\n     */\n    getLayerSeries: function () {\n        var data = this.getData();\n        var lenCount = data.count();\n        var indexArr = [];\n\n        for (var i = 0; i < lenCount; ++i) {\n            indexArr[i] = i;\n        }\n        // data group by name\n        var dataByName = nest()\n            .key(function (index) {\n                return data.get('name', index);\n            })\n            .entries(indexArr);\n\n        var layerSeries = map(dataByName, function (d) {\n            return {\n                name: d.key,\n                indices: d.values\n            };\n        });\n\n        var timeDim = data.mapDimension('single');\n\n        for (var j = 0; j < layerSeries.length; ++j) {\n            layerSeries[j].indices.sort(comparer);\n        }\n\n        function comparer(index1, index2) {\n            return data.get(timeDim, index1) - data.get(timeDim, index2);\n        }\n\n        return layerSeries;\n    },\n\n    /**\n     * Get data indices for show tooltip content\n     *\n     * @param {Array.<string>|string} dim  single coordinate dimension\n     * @param {number} value axis value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis  single Axis used\n     *     the themeRiver.\n     * @return {Object} {dataIndices, nestestValue}\n     */\n    getAxisTooltipData: function (dim, value, baseAxis) {\n        if (!isArray(dim)) {\n            dim = dim ? [dim] : [];\n        }\n\n        var data = this.getData();\n        var layerSeries = this.getLayerSeries();\n        var indices = [];\n        var layerNum = layerSeries.length;\n        var nestestValue;\n\n        for (var i = 0; i < layerNum; ++i) {\n            var minDist = Number.MAX_VALUE;\n            var nearestIdx = -1;\n            var pointNum = layerSeries[i].indices.length;\n            for (var j = 0; j < pointNum; ++j) {\n                var theValue = data.get(dim[0], layerSeries[i].indices[j]);\n                var dist = Math.abs(theValue - value);\n                if (dist <= minDist) {\n                    nestestValue = theValue;\n                    minDist = dist;\n                    nearestIdx = layerSeries[i].indices[j];\n                }\n            }\n            indices.push(nearestIdx);\n        }\n\n        return {dataIndices: indices, nestestValue: nestestValue};\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex  index of data\n     */\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var htmlName = data.getName(dataIndex);\n        var htmlValue = data.get(data.mapDimension('value'), dataIndex);\n        if (isNaN(htmlValue) || htmlValue == null) {\n            htmlValue = '-';\n        }\n        return encodeHTML(htmlName + ' : ' + htmlValue);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'singleAxis',\n\n        // gap in axis's orthogonal orientation\n        boundaryGap: ['10%', '10%'],\n\n        // legendHoverLink: true,\n\n        singleAxisIndex: 0,\n\n        animationEasing: 'linear',\n\n        label: {\n            margin: 4,\n            show: true,\n            position: 'left',\n            color: '#000',\n            fontSize: 11\n        },\n\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  The file used to draw themeRiver view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nextendChartView({\n\n    type: 'themeRiver',\n\n    init: function () {\n        this._layers = [];\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var group = this.group;\n\n        var layerSeries = seriesModel.getLayerSeries();\n\n        var layoutInfo = data.getLayout('layoutInfo');\n        var rect = layoutInfo.rect;\n        var boundaryGap = layoutInfo.boundaryGap;\n\n        group.attr('position', [0, rect.y + boundaryGap[0]]);\n\n        function keyGetter(item) {\n            return item.name;\n        }\n        var dataDiffer = new DataDiffer(\n            this._layersSeries || [], layerSeries,\n            keyGetter, keyGetter\n        );\n\n        var newLayersGroups = {};\n\n        dataDiffer\n            .add(bind(process, this, 'add'))\n            .update(bind(process, this, 'update'))\n            .remove(bind(process, this, 'remove'))\n            .execute();\n\n        function process(status, idx, oldIdx) {\n            var oldLayersGroups = this._layers;\n            if (status === 'remove') {\n                group.remove(oldLayersGroups[idx]);\n                return;\n            }\n            var points0 = [];\n            var points1 = [];\n            var color;\n            var indices = layerSeries[idx].indices;\n            for (var j = 0; j < indices.length; j++) {\n                var layout = data.getItemLayout(indices[j]);\n                var x = layout.x;\n                var y0 = layout.y0;\n                var y = layout.y;\n\n                points0.push([x, y0]);\n                points1.push([x, y0 + y]);\n\n                color = data.getItemVisual(indices[j], 'color');\n            }\n\n            var polygon;\n            var text;\n            var textLayout = data.getItemLayout(indices[0]);\n            var itemModel = data.getItemModel(indices[j - 1]);\n            var labelModel = itemModel.getModel('label');\n            var margin = labelModel.get('margin');\n            if (status === 'add') {\n                var layerGroup = newLayersGroups[idx] = new Group();\n                polygon = new Polygon$1({\n                    shape: {\n                        points: points0,\n                        stackedOnPoints: points1,\n                        smooth: 0.4,\n                        stackedOnSmooth: 0.4,\n                        smoothConstraint: false\n                    },\n                    z2: 0\n                });\n                text = new Text({\n                    style: {\n                        x: textLayout.x - margin,\n                        y: textLayout.y0 + textLayout.y / 2\n                    }\n                });\n                layerGroup.add(polygon);\n                layerGroup.add(text);\n                group.add(layerGroup);\n\n                polygon.setClipPath(createGridClipShape$3(polygon.getBoundingRect(), seriesModel, function () {\n                    polygon.removeClipPath();\n                }));\n            }\n            else {\n                var layerGroup = oldLayersGroups[oldIdx];\n                polygon = layerGroup.childAt(0);\n                text = layerGroup.childAt(1);\n                group.add(layerGroup);\n\n                newLayersGroups[idx] = layerGroup;\n\n                updateProps(polygon, {\n                    shape: {\n                        points: points0,\n                        stackedOnPoints: points1\n                    }\n                }, seriesModel);\n\n                updateProps(text, {\n                    style: {\n                        x: textLayout.x - margin,\n                        y: textLayout.y0 + textLayout.y / 2\n                    }\n                }, seriesModel);\n            }\n\n            var hoverItemStyleModel = itemModel.getModel('emphasis.itemStyle');\n            var itemStyleModel = itemModel.getModel('itemStyle');\n\n            setTextStyle(text.style, labelModel, {\n                text: labelModel.get('show')\n                    ? seriesModel.getFormattedLabel(indices[j - 1], 'normal')\n                        || data.getName(indices[j - 1])\n                    : null,\n                textVerticalAlign: 'middle'\n            });\n\n            polygon.setStyle(extend({\n                fill: color\n            }, itemStyleModel.getItemStyle(['color'])));\n\n            setHoverStyle(polygon, hoverItemStyleModel.getItemStyle());\n        }\n\n        this._layersSeries = layerSeries;\n        this._layers = newLayersGroups;\n    },\n\n    dispose: function () {}\n});\n\n// add animation to the view\nfunction createGridClipShape$3(rect, seriesModel, cb) {\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x - 10,\n            y: rect.y - 10,\n            width: 0,\n            height: rect.height + 20\n        }\n    });\n    initProps(rectEl, {\n        shape: {\n            width: rect.width + 20,\n            height: rect.height + 20\n        }\n    }, seriesModel, cb);\n\n    return rectEl;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  Using layout algorithm transform the raw data to layout information.\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar themeRiverLayout = function (ecModel, api) {\n\n    ecModel.eachSeriesByType('themeRiver', function (seriesModel) {\n\n        var data = seriesModel.getData();\n\n        var single = seriesModel.coordinateSystem;\n\n        var layoutInfo = {};\n\n        // use the axis boundingRect for view\n        var rect = single.getRect();\n\n        layoutInfo.rect = rect;\n\n        var boundaryGap = seriesModel.get('boundaryGap');\n\n        var axis = single.getAxis();\n\n        layoutInfo.boundaryGap = boundaryGap;\n\n        if (axis.orient === 'horizontal') {\n            boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.height);\n            boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.height);\n            var height = rect.height - boundaryGap[0] - boundaryGap[1];\n            themeRiverLayout$1(data, seriesModel, height);\n        }\n        else {\n            boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.width);\n            boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.width);\n            var width = rect.width - boundaryGap[0] - boundaryGap[1];\n            themeRiverLayout$1(data, seriesModel, width);\n        }\n\n        data.setLayout('layoutInfo', layoutInfo);\n    });\n};\n\n/**\n * The layout information about themeriver\n *\n * @param {module:echarts/data/List} data  data in the series\n * @param {module:echarts/model/Series} seriesModel  the model object of themeRiver series\n * @param {number} height  value used to compute every series height\n */\nfunction themeRiverLayout$1(data, seriesModel, height) {\n    if (!data.count()) {\n        return;\n    }\n    var coordSys = seriesModel.coordinateSystem;\n    // the data in each layer are organized into a series.\n    var layerSeries = seriesModel.getLayerSeries();\n\n    // the points in each layer.\n    var timeDim = data.mapDimension('single');\n    var valueDim = data.mapDimension('value');\n    var layerPoints = map(layerSeries, function (singleLayer) {\n        return map(singleLayer.indices, function (idx) {\n            var pt = coordSys.dataToPoint(data.get(timeDim, idx));\n            pt[1] = data.get(valueDim, idx);\n            return pt;\n        });\n    });\n\n    var base = computeBaseline(layerPoints);\n    var baseLine = base.y0;\n    var ky = height / base.max;\n\n    // set layout information for each item.\n    var n = layerSeries.length;\n    var m = layerSeries[0].indices.length;\n    var baseY0;\n    for (var j = 0; j < m; ++j) {\n        baseY0 = baseLine[j] * ky;\n        data.setItemLayout(layerSeries[0].indices[j], {\n            layerIndex: 0,\n            x: layerPoints[0][j][0],\n            y0: baseY0,\n            y: layerPoints[0][j][1] * ky\n        });\n        for (var i = 1; i < n; ++i) {\n            baseY0 += layerPoints[i - 1][j][1] * ky;\n            data.setItemLayout(layerSeries[i].indices[j], {\n                layerIndex: i,\n                x: layerPoints[i][j][0],\n                y0: baseY0,\n                y: layerPoints[i][j][1] * ky\n            });\n        }\n    }\n}\n\n/**\n * Compute the baseLine of the rawdata\n * Inspired by Lee Byron's paper Stacked Graphs - Geometry & Aesthetics\n *\n * @param  {Array.<Array>} data  the points in each layer\n * @return {Object}\n */\nfunction computeBaseline(data) {\n    var layerNum = data.length;\n    var pointNum = data[0].length;\n    var sums = [];\n    var y0 = [];\n    var max = 0;\n    var temp;\n    var base = {};\n\n    for (var i = 0; i < pointNum; ++i) {\n        for (var j = 0, temp = 0; j < layerNum; ++j) {\n            temp += data[j][i][1];\n        }\n        if (temp > max) {\n            max = temp;\n        }\n        sums.push(temp);\n    }\n\n    for (var k = 0; k < pointNum; ++k) {\n        y0[k] = (max - sums[k]) / 2;\n    }\n    max = 0;\n\n    for (var l = 0; l < pointNum; ++l) {\n        var sum = sums[l] + y0[l];\n        if (sum > max) {\n            max = sum;\n        }\n    }\n    base.y0 = y0;\n    base.max = max;\n\n    return base;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual encoding for themeRiver view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar themeRiverVisual = function (ecModel) {\n    ecModel.eachSeriesByType('themeRiver', function (seriesModel) {\n        var data = seriesModel.getData();\n        var rawData = seriesModel.getRawData();\n        var colorList = seriesModel.get('color');\n        var idxMap = createHashMap();\n\n        data.each(function (idx) {\n            idxMap.set(data.getRawIndex(idx), idx);\n        });\n\n        rawData.each(function (rawIndex) {\n            var name = rawData.getName(rawIndex);\n            var color = colorList[(seriesModel.nameMap.get(name) - 1) % colorList.length];\n\n            rawData.setItemVisual(rawIndex, 'color', color);\n\n            var idx = idxMap.get(rawIndex);\n\n            if (idx != null) {\n                data.setItemVisual(idx, 'color', color);\n            }\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(themeRiverLayout);\nregisterVisual(themeRiverVisual);\nregisterProcessor(dataFilter('themeRiver'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.sunburst',\n\n    /**\n     * @type {module:echarts/data/Tree~Node}\n     */\n    _viewRoot: null,\n\n    getInitialData: function (option, ecModel) {\n        // Create a virtual root.\n        var root = { name: option.name, children: option.data };\n\n        completeTreeValue$1(root);\n\n        var levels = option.levels || [];\n\n        // levels = option.levels = setDefault(levels, ecModel);\n\n        var treeOption = {};\n\n        treeOption.levels = levels;\n\n        // Make sure always a new tree is created when setOption,\n        // in TreemapView, we check whether oldTree === newTree\n        // to choose mappings approach among old shapes and new shapes.\n        return Tree.createTree(root, this, treeOption).data;\n    },\n\n    optionUpdated: function () {\n        this.resetViewRoot();\n    },\n\n    /*\n     * @override\n     */\n    getDataParams: function (dataIndex) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n\n        var node = this.getData().tree.getNodeByDataIndex(dataIndex);\n        params.treePathInfo = wrapTreePathInfo(node, this);\n\n        return params;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // Policy of highlighting pieces when hover on one\n        // Valid values: 'none' (for not downplay others), 'descendant',\n        // 'ancestor', 'self'\n        highlightPolicy: 'descendant',\n\n        // 'rootToNode', 'link', or false\n        nodeClick: 'rootToNode',\n\n        renderLabelForZeroData: false,\n\n        label: {\n            // could be: 'radial', 'tangential', or 'none'\n            rotate: 'radial',\n            show: true,\n            opacity: 1,\n            // 'left' is for inner side of inside, and 'right' is for outter\n            // side for inside\n            align: 'center',\n            position: 'inside',\n            distance: 5,\n            silent: true,\n            emphasis: {}\n        },\n        itemStyle: {\n            borderWidth: 1,\n            borderColor: 'white',\n            borderType: 'solid',\n            shadowBlur: 0,\n            shadowColor: 'rgba(0, 0, 0, 0.2)',\n            shadowOffsetX: 0,\n            shadowOffsetY: 0,\n            opacity: 1,\n            emphasis: {},\n            highlight: {\n                opacity: 1\n            },\n            downplay: {\n                opacity: 0.9\n            }\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n        animationDuration: 1000,\n        animationDurationUpdate: 500,\n        animationEasing: 'cubicOut',\n\n        data: [],\n\n        levels: [],\n\n        /**\n         * Sort order.\n         *\n         * Valid values: 'desc', 'asc', null, or callback function.\n         * 'desc' and 'asc' for descend and ascendant order;\n         * null for not sorting;\n         * example of callback function:\n         * function(nodeA, nodeB) {\n         *     return nodeA.getValue() - nodeB.getValue();\n         * }\n         */\n        sort: 'desc'\n    },\n\n    getViewRoot: function () {\n        return this._viewRoot;\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~Node} [viewRoot]\n     */\n    resetViewRoot: function (viewRoot) {\n        viewRoot\n            ? (this._viewRoot = viewRoot)\n            : (viewRoot = this._viewRoot);\n\n        var root = this.getRawData().tree.root;\n\n        if (!viewRoot\n            || (viewRoot !== root && !root.contains(viewRoot))\n        ) {\n            this._viewRoot = root;\n        }\n    }\n});\n\n\n\n/**\n * @param {Object} dataNode\n */\nfunction completeTreeValue$1(dataNode) {\n    // Postorder travel tree.\n    // If value of none-leaf node is not set,\n    // calculate it by suming up the value of all children.\n    var sum = 0;\n\n    each$1(dataNode.children, function (child) {\n\n        completeTreeValue$1(child);\n\n        var childValue = child.value;\n        isArray(childValue) && (childValue = childValue[0]);\n\n        sum += childValue;\n    });\n\n    var thisValue = dataNode.value;\n    if (isArray(thisValue)) {\n        thisValue = thisValue[0];\n    }\n\n    if (thisValue == null || isNaN(thisValue)) {\n        thisValue = sum;\n    }\n    // Value should not less than 0.\n    if (thisValue < 0) {\n        thisValue = 0;\n    }\n\n    isArray(dataNode.value)\n        ? (dataNode.value[0] = thisValue)\n        : (dataNode.value = thisValue);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NodeHighlightPolicy = {\n    NONE: 'none', // not downplay others\n    DESCENDANT: 'descendant',\n    ANCESTOR: 'ancestor',\n    SELF: 'self'\n};\n\nvar DEFAULT_SECTOR_Z = 2;\nvar DEFAULT_TEXT_Z = 4;\n\n/**\n * Sunburstce of Sunburst including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction SunburstPiece(node, seriesModel, ecModel) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: DEFAULT_SECTOR_Z\n    });\n    sector.seriesIndex = seriesModel.seriesIndex;\n\n    var text = new Text({\n        z2: DEFAULT_TEXT_Z,\n        silent: node.getModel('label').get('silent')\n    });\n    this.add(sector);\n    this.add(text);\n\n    this.updateData(true, node, 'normal', seriesModel, ecModel);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar SunburstPieceProto = SunburstPiece.prototype;\n\nSunburstPieceProto.updateData = function (\n    firstCreate,\n    node,\n    state,\n    seriesModel,\n    ecModel\n) {\n    this.node = node;\n    node.piece = this;\n\n    seriesModel = seriesModel || this._seriesModel;\n    ecModel = ecModel || this._ecModel;\n\n    var sector = this.childAt(0);\n    sector.dataIndex = node.dataIndex;\n\n    var itemModel = node.getModel();\n    var layout = node.getLayout();\n    // if (!layout) {\n    //     console.log(node.getLayout());\n    // }\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    var visualColor = getNodeColor(node, seriesModel, ecModel);\n\n    fillDefaultColor(node, seriesModel, visualColor);\n\n    var normalStyle = itemModel.getModel('itemStyle').getItemStyle();\n    var style;\n    if (state === 'normal') {\n        style = normalStyle;\n    }\n    else {\n        var stateStyle = itemModel.getModel(state + '.itemStyle')\n            .getItemStyle();\n        style = merge(stateStyle, normalStyle);\n    }\n    style = defaults(\n        {\n            lineJoin: 'bevel',\n            fill: style.fill || visualColor\n        },\n        style\n    );\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n        sector.shape.r = layout.r0;\n        updateProps(\n            sector,\n            {\n                shape: {\n                    r: layout.r\n                }\n            },\n            seriesModel,\n            node.dataIndex\n        );\n        sector.useStyle(style);\n    }\n    else if (typeof style.fill === 'object' && style.fill.type\n        || typeof sector.style.fill === 'object' && sector.style.fill.type\n    ) {\n        // Disable animation for gradient since no interpolation method\n        // is supported for gradient\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel);\n        sector.useStyle(style);\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape,\n            style: style\n        }, seriesModel);\n    }\n\n    this._updateLabel(seriesModel, visualColor, state);\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    if (firstCreate) {\n        var highlightPolicy = seriesModel.getShallow('highlightPolicy');\n        this._initEvents(sector, node, seriesModel, highlightPolicy);\n    }\n\n    this._seriesModel = seriesModel || this._seriesModel;\n    this._ecModel = ecModel || this._ecModel;\n};\n\nSunburstPieceProto.onEmphasis = function (highlightPolicy) {\n    var that = this;\n    this.node.hostTree.root.eachNode(function (n) {\n        if (n.piece) {\n            if (that.node === n) {\n                n.piece.updateData(false, n, 'emphasis');\n            }\n            else if (isNodeHighlighted(n, that.node, highlightPolicy)) {\n                n.piece.childAt(0).trigger('highlight');\n            }\n            else if (highlightPolicy !== NodeHighlightPolicy.NONE) {\n                n.piece.childAt(0).trigger('downplay');\n            }\n        }\n    });\n};\n\nSunburstPieceProto.onNormal = function () {\n    this.node.hostTree.root.eachNode(function (n) {\n        if (n.piece) {\n            n.piece.updateData(false, n, 'normal');\n        }\n    });\n};\n\nSunburstPieceProto.onHighlight = function () {\n    this.updateData(false, this.node, 'highlight');\n};\n\nSunburstPieceProto.onDownplay = function () {\n    this.updateData(false, this.node, 'downplay');\n};\n\nSunburstPieceProto._updateLabel = function (seriesModel, visualColor, state) {\n    var itemModel = this.node.getModel();\n    var normalModel = itemModel.getModel('label');\n    var labelModel = state === 'normal' || state === 'emphasis'\n        ? normalModel\n        : itemModel.getModel(state + '.label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n\n    var text = retrieve(\n        seriesModel.getFormattedLabel(\n            this.node.dataIndex, 'normal', null, null, 'label'\n        ),\n        this.node.name\n    );\n    if (getLabelAttr('show') === false) {\n        text = '';\n    }\n\n    var layout = this.node.getLayout();\n    var labelMinAngle = labelModel.get('minAngle');\n    if (labelMinAngle == null) {\n        labelMinAngle = normalModel.get('minAngle');\n    }\n    labelMinAngle = labelMinAngle / 180 * Math.PI;\n    var angle = layout.endAngle - layout.startAngle;\n    if (labelMinAngle != null && Math.abs(angle) < labelMinAngle) {\n        // Not displaying text when angle is too small\n        text = '';\n    }\n\n    var label = this.childAt(1);\n\n    setLabelStyle(\n        label.style, label.hoverStyle || {}, normalModel, labelHoverModel,\n        {\n            defaultText: labelModel.getShallow('show') ? text : null,\n            autoColor: visualColor,\n            useInsideStyle: true\n        }\n    );\n\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var r;\n    var labelPosition = getLabelAttr('position');\n    var labelPadding = getLabelAttr('distance') || 0;\n    var textAlign = getLabelAttr('align');\n    if (labelPosition === 'outside') {\n        r = layout.r + labelPadding;\n        textAlign = midAngle > Math.PI / 2 ? 'right' : 'left';\n    }\n    else {\n        if (!textAlign || textAlign === 'center') {\n            r = (layout.r + layout.r0) / 2;\n            textAlign = 'center';\n        }\n        else if (textAlign === 'left') {\n            r = layout.r0 + labelPadding;\n            if (midAngle > Math.PI / 2) {\n                textAlign = 'right';\n            }\n        }\n        else if (textAlign === 'right') {\n            r = layout.r - labelPadding;\n            if (midAngle > Math.PI / 2) {\n                textAlign = 'left';\n            }\n        }\n    }\n\n    label.attr('style', {\n        text: text,\n        textAlign: textAlign,\n        textVerticalAlign: getLabelAttr('verticalAlign') || 'middle',\n        opacity: getLabelAttr('opacity')\n    });\n\n    var textX = r * dx + layout.cx;\n    var textY = r * dy + layout.cy;\n    label.attr('position', [textX, textY]);\n\n    var rotateType = getLabelAttr('rotate');\n    var rotate = 0;\n    if (rotateType === 'radial') {\n        rotate = -midAngle;\n        if (rotate < -Math.PI / 2) {\n            rotate += Math.PI;\n        }\n    }\n    else if (rotateType === 'tangential') {\n        rotate = Math.PI / 2 - midAngle;\n        if (rotate > Math.PI / 2) {\n            rotate -= Math.PI;\n        }\n        else if (rotate < -Math.PI / 2) {\n            rotate += Math.PI;\n        }\n    } else if (typeof rotateType === 'number') {\n        rotate = rotateType * Math.PI / 180;\n    }\n    label.attr('rotation', rotate);\n\n    function getLabelAttr(name) {\n        var stateAttr = labelModel.get(name);\n        if (stateAttr == null) {\n            return normalModel.get(name);\n        }\n        else {\n            return stateAttr;\n        }\n    }\n};\n\nSunburstPieceProto._initEvents = function (\n    sector,\n    node,\n    seriesModel,\n    highlightPolicy\n) {\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n\n    var that = this;\n    var onEmphasis = function () {\n        that.onEmphasis(highlightPolicy);\n    };\n    var onNormal = function () {\n        that.onNormal();\n    };\n    var onDownplay = function () {\n        that.onDownplay();\n    };\n    var onHighlight = function () {\n        that.onHighlight();\n    };\n\n    if (seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal)\n            .on('downplay', onDownplay)\n            .on('highlight', onHighlight);\n    }\n};\n\ninherits(SunburstPiece, Group);\n\n/**\n * Get node color\n *\n * @param {TreeNode} node the node to get color\n * @param {module:echarts/model/Series} seriesModel series\n * @param {module:echarts/model/Global} ecModel echarts defaults\n */\nfunction getNodeColor(node, seriesModel, ecModel) {\n    // Color from visualMap\n    var visualColor = node.getVisual('color');\n    var visualMetaList = node.getVisual('visualMeta');\n    if (!visualMetaList || visualMetaList.length === 0) {\n        // Use first-generation color if has no visualMap\n        visualColor = null;\n    }\n\n    // Self color or level color\n    var color = node.getModel('itemStyle').get('color');\n    if (color) {\n        return color;\n    }\n    else if (visualColor) {\n        // Color mapping\n        return visualColor;\n    }\n    else if (node.depth === 0) {\n        // Virtual root node\n        return ecModel.option.color[0];\n    }\n    else {\n        // First-generation color\n        var length = ecModel.option.color.length;\n        color = ecModel.option.color[getRootId(node) % length];\n    }\n    return color;\n}\n\n/**\n * Get index of root in sorted order\n *\n * @param {TreeNode} node current node\n * @return {number} index in root\n */\nfunction getRootId(node) {\n    var ancestor = node;\n    while (ancestor.depth > 1) {\n        ancestor = ancestor.parentNode;\n    }\n\n    var virtualRoot = node.getAncestors()[0];\n    return indexOf(virtualRoot.children, ancestor);\n}\n\nfunction isNodeHighlighted(node, activeNode, policy) {\n    if (policy === NodeHighlightPolicy.NONE) {\n        return false;\n    }\n    else if (policy === NodeHighlightPolicy.SELF) {\n        return node === activeNode;\n    }\n    else if (policy === NodeHighlightPolicy.ANCESTOR) {\n        return node === activeNode || node.isAncestorOf(activeNode);\n    }\n    else {\n        return node === activeNode || node.isDescendantOf(activeNode);\n    }\n}\n\n// Fix tooltip callback function params.color incorrect when pick a default color\nfunction fillDefaultColor(node, seriesModel, color) {\n    var data = seriesModel.getData();\n    data.setItemVisual(node.dataIndex, 'color', color);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ROOT_TO_NODE_ACTION = 'sunburstRootToNode';\n\nvar SunburstView = Chart.extend({\n\n    type: 'sunburst',\n\n    init: function () {\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        var that = this;\n\n        this.seriesModel = seriesModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        var data = seriesModel.getData();\n        var virtualRoot = data.tree.root;\n\n        var newRoot = seriesModel.getViewRoot();\n\n        var group = this.group;\n\n        var renderLabelForZeroData = seriesModel.get('renderLabelForZeroData');\n\n        var newChildren = [];\n        newRoot.eachNode(function (node) {\n            newChildren.push(node);\n        });\n        var oldChildren = this._oldChildren || [];\n\n        dualTravel(newChildren, oldChildren);\n\n        renderRollUp(virtualRoot, newRoot);\n\n        if (payload && payload.highlight && payload.highlight.piece) {\n            var highlightPolicy = seriesModel.getShallow('highlightPolicy');\n            payload.highlight.piece.onEmphasis(highlightPolicy);\n        }\n        else if (payload && payload.unhighlight) {\n            var piece = this.virtualPiece;\n            if (!piece && virtualRoot.children.length) {\n                piece = virtualRoot.children[0].piece;\n            }\n            if (piece) {\n                piece.onNormal();\n            }\n        }\n\n        this._initEvents();\n\n        this._oldChildren = newChildren;\n\n        function dualTravel(newChildren, oldChildren) {\n            if (newChildren.length === 0 && oldChildren.length === 0) {\n                return;\n            }\n\n            new DataDiffer(oldChildren, newChildren, getKey, getKey)\n                .add(processNode)\n                .update(processNode)\n                .remove(curry(processNode, null))\n                .execute();\n\n            function getKey(node) {\n                return node.getId();\n            }\n\n            function processNode(newId, oldId) {\n                var newNode = newId == null ? null : newChildren[newId];\n                var oldNode = oldId == null ? null : oldChildren[oldId];\n\n                doRenderNode(newNode, oldNode);\n            }\n        }\n\n        function doRenderNode(newNode, oldNode) {\n            if (!renderLabelForZeroData && newNode && !newNode.getValue()) {\n                // Not render data with value 0\n                newNode = null;\n            }\n\n            if (newNode !== virtualRoot && oldNode !== virtualRoot) {\n                if (oldNode && oldNode.piece) {\n                    if (newNode) {\n                        // Update\n                        oldNode.piece.updateData(\n                            false, newNode, 'normal', seriesModel, ecModel);\n\n                        // For tooltip\n                        data.setItemGraphicEl(newNode.dataIndex, oldNode.piece);\n                    }\n                    else {\n                        // Remove\n                        removeNode(oldNode);\n                    }\n                }\n                else if (newNode) {\n                    // Add\n                    var piece = new SunburstPiece(\n                        newNode,\n                        seriesModel,\n                        ecModel\n                    );\n                    group.add(piece);\n\n                    // For tooltip\n                    data.setItemGraphicEl(newNode.dataIndex, piece);\n                }\n            }\n        }\n\n        function removeNode(node) {\n            if (!node) {\n                return;\n            }\n\n            if (node.piece) {\n                group.remove(node.piece);\n                node.piece = null;\n            }\n        }\n\n        function renderRollUp(virtualRoot, viewRoot) {\n            if (viewRoot.depth > 0) {\n                // Render\n                if (that.virtualPiece) {\n                    // Update\n                    that.virtualPiece.updateData(\n                        false, virtualRoot, 'normal', seriesModel, ecModel);\n                }\n                else {\n                    // Add\n                    that.virtualPiece = new SunburstPiece(\n                        virtualRoot,\n                        seriesModel,\n                        ecModel\n                    );\n                    group.add(that.virtualPiece);\n                }\n\n                if (viewRoot.piece._onclickEvent) {\n                    viewRoot.piece.off('click', viewRoot.piece._onclickEvent);\n                }\n                var event = function (e) {\n                    that._rootToNode(viewRoot.parentNode);\n                };\n                viewRoot.piece._onclickEvent = event;\n                that.virtualPiece.on('click', event);\n            }\n            else if (that.virtualPiece) {\n                // Remove\n                group.remove(that.virtualPiece);\n                that.virtualPiece = null;\n            }\n        }\n    },\n\n    dispose: function () {\n    },\n\n    /**\n     * @private\n     */\n    _initEvents: function () {\n        var that = this;\n\n        var event = function (e) {\n            var targetFound = false;\n            var viewRoot = that.seriesModel.getViewRoot();\n            viewRoot.eachNode(function (node) {\n                if (!targetFound\n                    && node.piece && node.piece.childAt(0) === e.target\n                ) {\n                    var nodeClick = node.getModel().get('nodeClick');\n                    if (nodeClick === 'rootToNode') {\n                        that._rootToNode(node);\n                    }\n                    else if (nodeClick === 'link') {\n                        var itemModel = node.getModel();\n                        var link = itemModel.get('link');\n                        if (link) {\n                            var linkTarget = itemModel.get('target', true)\n                                || '_blank';\n                            window.open(link, linkTarget);\n                        }\n                    }\n                    targetFound = true;\n                }\n            });\n        };\n\n        if (this.group._onclickEvent) {\n            this.group.off('click', this.group._onclickEvent);\n        }\n        this.group.on('click', event);\n        this.group._onclickEvent = event;\n    },\n\n    /**\n     * @private\n     */\n    _rootToNode: function (node) {\n        if (node !== this.seriesModel.getViewRoot()) {\n            this.api.dispatchAction({\n                type: ROOT_TO_NODE_ACTION,\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                targetNode: node\n            });\n        }\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var treeRoot = seriesModel.getData();\n        var itemLayout = treeRoot.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Sunburst action\n */\n\nvar ROOT_TO_NODE_ACTION$1 = 'sunburstRootToNode';\n\nregisterAction(\n    {type: ROOT_TO_NODE_ACTION$1, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleRootToNode\n        );\n\n        function handleRootToNode(model, index) {\n            var targetInfo = retrieveTargetInfo(payload, [ROOT_TO_NODE_ACTION$1], model);\n\n            if (targetInfo) {\n                var originViewRoot = model.getViewRoot();\n                if (originViewRoot) {\n                    payload.direction = aboveViewRoot(originViewRoot, targetInfo.node)\n                        ? 'rollUp' : 'drillDown';\n                }\n                model.resetViewRoot(targetInfo.node);\n            }\n        }\n    }\n);\n\n\nvar HIGHLIGHT_ACTION = 'sunburstHighlight';\n\nregisterAction(\n    {type: HIGHLIGHT_ACTION, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleHighlight\n        );\n\n        function handleHighlight(model, index) {\n            var targetInfo = retrieveTargetInfo(payload, [HIGHLIGHT_ACTION], model);\n\n            if (targetInfo) {\n                payload.highlight = targetInfo.node;\n            }\n        }\n    }\n);\n\n\nvar UNHIGHLIGHT_ACTION = 'sunburstUnhighlight';\n\nregisterAction(\n    {type: UNHIGHLIGHT_ACTION, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleUnhighlight\n        );\n\n        function handleUnhighlight(model, index) {\n            payload.unhighlight = true;\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar RADIAN$1 = Math.PI / 180;\n\nvar sunburstLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN$1;\n        var minAngle = seriesModel.get('minAngle') * RADIAN$1;\n\n        var virtualRoot = seriesModel.getData().tree.root;\n        var treeRoot = seriesModel.getViewRoot();\n        var rootDepth = treeRoot.depth;\n\n        var sort = seriesModel.get('sort');\n        if (sort != null) {\n            initChildren$1(treeRoot, sort);\n        }\n\n        var validDataCount = 0;\n        each$1(treeRoot.children, function (child) {\n            !isNaN(child.getValue()) && validDataCount++;\n        });\n\n        var sum = treeRoot.getValue();\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var renderRollupNode = treeRoot.depth > 0;\n        var levels = treeRoot.height - (renderRollupNode ? -1 : 1);\n        var rPerLevel = (r - r0) / (levels || 1);\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // In the case some sector angle is smaller than minAngle\n        var dir = clockwise ? 1 : -1;\n\n        /**\n         * Render a tree\n         * @return increased angle\n         */\n        var renderNode = function (node, startAngle) {\n            if (!node) {\n                return;\n            }\n\n            var endAngle = startAngle;\n\n            // Render self\n            if (node !== virtualRoot) {\n                // Tree node is virtual, so it doesn't need to be drawn\n                var value = node.getValue();\n\n                var angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n                if (angle < minAngle) {\n                    angle = minAngle;\n                    \n                }\n                else {\n                    \n                }\n\n                endAngle = startAngle + dir * angle;\n\n                var depth = node.depth - rootDepth\n                    - (renderRollupNode ? -1 : 1);\n                var rStart = r0 + rPerLevel * depth;\n                var rEnd = r0 + rPerLevel * (depth + 1);\n\n                var itemModel = node.getModel();\n                if (itemModel.get('r0') != null) {\n                    rStart = parsePercent$1(itemModel.get('r0'), size / 2);\n                }\n                if (itemModel.get('r') != null) {\n                    rEnd = parsePercent$1(itemModel.get('r'), size / 2);\n                }\n\n                node.setLayout({\n                    angle: angle,\n                    startAngle: startAngle,\n                    endAngle: endAngle,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: rStart,\n                    r: rEnd\n                });\n            }\n\n            // Render children\n            if (node.children && node.children.length) {\n                // currentAngle = startAngle;\n                var siblingAngle = 0;\n                each$1(node.children, function (node) {\n                    siblingAngle += renderNode(node, startAngle + siblingAngle);\n                });\n            }\n\n            return endAngle - startAngle;\n        };\n\n        // Virtual root node for roll up\n        if (renderRollupNode) {\n            var rStart = r0;\n            var rEnd = r0 + rPerLevel;\n\n            var angle = Math.PI * 2;\n            virtualRoot.setLayout({\n                angle: angle,\n                startAngle: startAngle,\n                endAngle: startAngle + angle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: rStart,\n                r: rEnd\n            });\n        }\n\n        renderNode(treeRoot, startAngle);\n    });\n};\n\n/**\n * Init node children by order and update visual\n *\n * @param {TreeNode} node  root node\n * @param {boolean}  isAsc if is in ascendant order\n */\nfunction initChildren$1(node, isAsc) {\n    var children = node.children || [];\n\n    node.children = sort$2(children, isAsc);\n\n    // Init children recursively\n    if (children.length) {\n        each$1(node.children, function (child) {\n            initChildren$1(child, isAsc);\n        });\n    }\n}\n\n/**\n * Sort children nodes\n *\n * @param {TreeNode[]}               children children of node to be sorted\n * @param {string | function | null} sort sort method\n *                                   See SunburstSeries.js for details.\n */\nfunction sort$2(children, sortOrder) {\n    if (typeof sortOrder === 'function') {\n        return children.sort(sortOrder);\n    }\n    else {\n        var isAsc = sortOrder === 'asc';\n        return children.sort(function (a, b) {\n            var diff = (a.getValue() - b.getValue()) * (isAsc ? 1 : -1);\n            return diff === 0\n                ? (a.dataIndex - b.dataIndex) * (isAsc ? -1 : 1)\n                : diff;\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(curry(dataColor, 'sunburst'));\nregisterLayout(curry(sunburstLayout, 'sunburst'));\nregisterProcessor(curry(dataFilter, 'sunburst'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    dataItem = dataItem || [0, 0];\n    return map(['x', 'y'], function (dim, dimIdx) {\n        var axis = this.getAxis(dim);\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        return axis.type === 'category'\n            ? axis.getBandWidth()\n            : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));\n    }, this);\n}\n\nvar prepareCartesian2d = function (coordSys) {\n    var rect = coordSys.grid.getRect();\n    return {\n        coordSys: {\n            // The name exposed to user is always 'cartesian2d' but not 'grid'.\n            type: 'cartesian2d',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: function (data) {\n                // do not provide \"out\" param\n                return coordSys.dataToPoint(data);\n            },\n            size: bind(dataToCoordSize, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$1(dataSize, dataItem) {\n    dataItem = dataItem || [0, 0];\n    return map([0, 1], function (dimIdx) {\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var p1 = [];\n        var p2 = [];\n        p1[dimIdx] = val - halfSize;\n        p2[dimIdx] = val + halfSize;\n        p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx];\n        return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]);\n    }, this);\n}\n\nvar prepareGeo = function (coordSys) {\n    var rect = coordSys.getBoundingRect();\n    return {\n        coordSys: {\n            type: 'geo',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height,\n            zoom: coordSys.getZoom()\n        },\n        api: {\n            coord: function (data) {\n                // do not provide \"out\" and noRoam param,\n                // Compatible with this usage:\n                // echarts.util.map(item.points, api.coord)\n                return coordSys.dataToPoint(data);\n            },\n            size: bind(dataToCoordSize$1, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$2(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    var axis = this.getAxis();\n    var val = dataItem instanceof Array ? dataItem[0] : dataItem;\n    var halfSize = (dataSize instanceof Array ? dataSize[0] : dataSize) / 2;\n    return axis.type === 'category'\n        ? axis.getBandWidth()\n        : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));\n}\n\nvar prepareSingleAxis = function (coordSys) {\n    var rect = coordSys.getRect();\n\n    return {\n        coordSys: {\n            type: 'singleAxis',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: function (val) {\n                // do not provide \"out\" param\n                return coordSys.dataToPoint(val);\n            },\n            size: bind(dataToCoordSize$2, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$3(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    return map(['Radius', 'Angle'], function (dim, dimIdx) {\n        var axis = this['get' + dim + 'Axis']();\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var method = 'dataTo' + dim;\n\n        var result = axis.type === 'category'\n            ? axis.getBandWidth()\n            : Math.abs(axis[method](val - halfSize) - axis[method](val + halfSize));\n\n        if (dim === 'Angle') {\n            result = result * Math.PI / 180;\n        }\n\n        return result;\n\n    }, this);\n}\n\nvar preparePolar = function (coordSys) {\n    var radiusAxis = coordSys.getRadiusAxis();\n    var angleAxis = coordSys.getAngleAxis();\n    var radius = radiusAxis.getExtent();\n    radius[0] > radius[1] && radius.reverse();\n\n    return {\n        coordSys: {\n            type: 'polar',\n            cx: coordSys.cx,\n            cy: coordSys.cy,\n            r: radius[1],\n            r0: radius[0]\n        },\n        api: {\n            coord: bind(function (data) {\n                var radius = radiusAxis.dataToRadius(data[0]);\n                var angle = angleAxis.dataToAngle(data[1]);\n                var coord = coordSys.coordToPoint([radius, angle]);\n                coord.push(radius, angle * Math.PI / 180);\n                return coord;\n            }),\n            size: bind(dataToCoordSize$3, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar prepareCalendar = function (coordSys) {\n    var rect = coordSys.getRect();\n    var rangeInfo = coordSys.getRangeInfo();\n\n    return {\n        coordSys: {\n            type: 'calendar',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height,\n            cellWidth: coordSys.getCellWidth(),\n            cellHeight: coordSys.getCellHeight(),\n            rangeInfo: {\n                start: rangeInfo.start,\n                end: rangeInfo.end,\n                weeks: rangeInfo.weeks,\n                dayCount: rangeInfo.allDay\n            }\n        },\n        api: {\n            coord: function (data, clamp) {\n                return coordSys.dataToPoint(data, clamp);\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ITEM_STYLE_NORMAL_PATH = ['itemStyle'];\nvar ITEM_STYLE_EMPHASIS_PATH = ['emphasis', 'itemStyle'];\nvar LABEL_NORMAL = ['label'];\nvar LABEL_EMPHASIS = ['emphasis', 'label'];\n// Use prefix to avoid index to be the same as el.name,\n// which will cause weird udpate animation.\nvar GROUP_DIFF_PREFIX = 'e\\0\\0';\n\n/**\n * To reduce total package size of each coordinate systems, the modules `prepareCustom`\n * of each coordinate systems are not required by each coordinate systems directly, but\n * required by the module `custom`.\n *\n * prepareInfoForCustomSeries {Function}: optional\n *     @return {Object} {coordSys: {...}, api: {\n *         coord: function (data, clamp) {}, // return point in global.\n *         size: function (dataSize, dataItem) {} // return size of each axis in coordSys.\n *     }}\n */\nvar prepareCustoms = {\n    cartesian2d: prepareCartesian2d,\n    geo: prepareGeo,\n    singleAxis: prepareSingleAxis,\n    polar: preparePolar,\n    calendar: prepareCalendar\n};\n\n\n// ------\n// Model\n// ------\n\nSeriesModel.extend({\n\n    type: 'series.custom',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d', // Can be set as 'none'\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        useTransform: true\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // label: {}\n        // itemStyle: {}\n    },\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    /**\n     * @override\n     */\n    getDataParams: function (dataIndex, dataType, el) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n        el && (params.info = el.info);\n        return params;\n    }\n});\n\n// -----\n// View\n// -----\n\nChart.extend({\n\n    type: 'custom',\n\n    /**\n     * @private\n     * @type {module:echarts/data/List}\n     */\n    _data: null,\n\n    /**\n     * @override\n     */\n    render: function (customSeries, ecModel, api, payload) {\n        var oldData = this._data;\n        var data = customSeries.getData();\n        var group = this.group;\n        var renderItem = makeRenderItem(customSeries, data, ecModel, api);\n\n        // By default, merge mode is applied. In most cases, custom series is\n        // used in the scenario that data amount is not large but graphic elements\n        // is complicated, where merge mode is probably necessary for optimization.\n        // For example, reuse graphic elements and only update the transform when\n        // roam or data zoom according to `actionType`.\n        data.diff(oldData)\n            .add(function (newIdx) {\n                createOrUpdate$1(\n                    null, newIdx, renderItem(newIdx, payload), customSeries, group, data\n                );\n            })\n            .update(function (newIdx, oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                createOrUpdate$1(\n                    el, newIdx, renderItem(newIdx, payload), customSeries, group, data\n                );\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    incrementalPrepareRender: function (customSeries, ecModel, api) {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    incrementalRender: function (params, customSeries, ecModel, api, payload) {\n        var data = customSeries.getData();\n        var renderItem = makeRenderItem(customSeries, data, ecModel, api);\n        function setIncrementalAndHoverLayer(el) {\n            if (!el.isGroup) {\n                el.incremental = true;\n                el.useHoverLayer = true;\n            }\n        }\n        for (var idx = params.start; idx < params.end; idx++) {\n            var el = createOrUpdate$1(null, idx, renderItem(idx, payload), customSeries, this.group, data);\n            el.traverse(setIncrementalAndHoverLayer);\n        }\n    },\n\n    /**\n     * @override\n     */\n    dispose: noop,\n\n    /**\n     * @override\n     */\n    filterForExposedEvent: function (eventType, query, targetEl, packedEvent) {\n        var elementName = query.element;\n        if (elementName == null || targetEl.name === elementName) {\n            return true;\n        }\n\n        // Enable to give a name on a group made by `renderItem`, and listen\n        // events that triggerd by its descendents.\n        while ((targetEl = targetEl.parent) && targetEl !== this.group) {\n            if (targetEl.name === elementName) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n});\n\n\nfunction createEl(elOption) {\n    var graphicType = elOption.type;\n    var el;\n\n    if (graphicType === 'path') {\n        var shape = elOption.shape;\n        // Using pathRect brings convenience to users sacle svg path.\n        var pathRect = (shape.width != null && shape.height != null)\n            ? {\n                x: shape.x || 0,\n                y: shape.y || 0,\n                width: shape.width,\n                height: shape.height\n            }\n            : null;\n        var pathData = getPathData(shape);\n        // Path is also used for icon, so layout 'center' by default.\n        el = makePath(pathData, null, pathRect, shape.layout || 'center');\n        el.__customPathData = pathData;\n    }\n    else if (graphicType === 'image') {\n        el = new ZImage({});\n        el.__customImagePath = elOption.style.image;\n    }\n    else if (graphicType === 'text') {\n        el = new Text({});\n        el.__customText = elOption.style.text;\n    }\n    else {\n        var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n        if (__DEV__) {\n            assert$1(Clz, 'graphic type \"' + graphicType + '\" can not be found.');\n        }\n\n        el = new Clz();\n    }\n\n    el.__customGraphicType = graphicType;\n    el.name = elOption.name;\n\n    return el;\n}\n\nfunction updateEl(el, dataIndex, elOption, animatableModel, data, isInit, isRoot) {\n    var transitionProps = {};\n    var elOptionStyle = elOption.style || {};\n\n    elOption.shape && (transitionProps.shape = clone(elOption.shape));\n    elOption.position && (transitionProps.position = elOption.position.slice());\n    elOption.scale && (transitionProps.scale = elOption.scale.slice());\n    elOption.origin && (transitionProps.origin = elOption.origin.slice());\n    elOption.rotation && (transitionProps.rotation = elOption.rotation);\n\n    if (el.type === 'image' && elOption.style) {\n        var targetStyle = transitionProps.style = {};\n        each$1(['x', 'y', 'width', 'height'], function (prop) {\n            prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);\n        });\n    }\n\n    if (el.type === 'text' && elOption.style) {\n        var targetStyle = transitionProps.style = {};\n        each$1(['x', 'y'], function (prop) {\n            prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);\n        });\n        // Compatible with previous: both support\n        // textFill and fill, textStroke and stroke in 'text' element.\n        !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n            elOptionStyle.textFill = elOptionStyle.fill\n        );\n        !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n            elOptionStyle.textStroke = elOptionStyle.stroke\n        );\n    }\n\n    if (el.type !== 'group') {\n        el.useStyle(elOptionStyle);\n\n        // Init animation.\n        if (isInit) {\n            el.style.opacity = 0;\n            var targetOpacity = elOptionStyle.opacity;\n            targetOpacity == null && (targetOpacity = 1);\n            initProps(el, {style: {opacity: targetOpacity}}, animatableModel, dataIndex);\n        }\n    }\n\n    if (isInit) {\n        el.attr(transitionProps);\n    }\n    else {\n        updateProps(el, transitionProps, animatableModel, dataIndex);\n    }\n\n    // Merge by default.\n    // z2 must not be null/undefined, otherwise sort error may occur.\n    elOption.hasOwnProperty('z2') && el.attr('z2', elOption.z2 || 0);\n    elOption.hasOwnProperty('silent') && el.attr('silent', elOption.silent);\n    elOption.hasOwnProperty('invisible') && el.attr('invisible', elOption.invisible);\n    elOption.hasOwnProperty('ignore') && el.attr('ignore', elOption.ignore);\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    // Update them only when user specified, otherwise, remain.\n    elOption.hasOwnProperty('info') && el.attr('info', elOption.info);\n\n    // If `elOption.styleEmphasis` is `false`, remove hover style. The\n    // logic is ensured by `graphicUtil.setElementHoverStyle`.\n    var styleEmphasis = elOption.styleEmphasis;\n    var disableStyleEmphasis = styleEmphasis === false;\n    if (!(\n        // Try to escapse setting hover style for performance.\n        (el.__cusHasEmphStl && styleEmphasis == null)\n        || (!el.__cusHasEmphStl && disableStyleEmphasis)\n    )) {\n        // Should not use graphicUtil.setHoverStyle, since the styleEmphasis\n        // should not be share by group and its descendants.\n        setElementHoverStyle(el, styleEmphasis);\n        el.__cusHasEmphStl = !disableStyleEmphasis;\n    }\n    isRoot && setAsHoverStyleTrigger(el, !disableStyleEmphasis);\n}\n\nfunction prepareStyleTransition(prop, targetStyle, elOptionStyle, oldElStyle, isInit) {\n    if (elOptionStyle[prop] != null && !isInit) {\n        targetStyle[prop] = elOptionStyle[prop];\n        elOptionStyle[prop] = oldElStyle[prop];\n    }\n}\n\nfunction makeRenderItem(customSeries, data, ecModel, api) {\n    var renderItem = customSeries.get('renderItem');\n    var coordSys = customSeries.coordinateSystem;\n    var prepareResult = {};\n\n    if (coordSys) {\n        if (__DEV__) {\n            assert$1(renderItem, 'series.render is required.');\n            assert$1(\n                coordSys.prepareCustoms || prepareCustoms[coordSys.type],\n                'This coordSys does not support custom series.'\n            );\n        }\n\n        prepareResult = coordSys.prepareCustoms\n            ? coordSys.prepareCustoms()\n            : prepareCustoms[coordSys.type](coordSys);\n    }\n\n    var userAPI = defaults({\n        getWidth: api.getWidth,\n        getHeight: api.getHeight,\n        getZr: api.getZr,\n        getDevicePixelRatio: api.getDevicePixelRatio,\n        value: value,\n        style: style,\n        styleEmphasis: styleEmphasis,\n        visual: visual,\n        barLayout: barLayout,\n        currentSeriesIndices: currentSeriesIndices,\n        font: font\n    }, prepareResult.api || {});\n\n    var userParams = {\n        // The life cycle of context: current round of rendering.\n        // The global life cycle is probably not necessary, because\n        // user can store global status by themselves.\n        context: {},\n        seriesId: customSeries.id,\n        seriesName: customSeries.name,\n        seriesIndex: customSeries.seriesIndex,\n        coordSys: prepareResult.coordSys,\n        dataInsideLength: data.count(),\n        encode: wrapEncodeDef(customSeries.getData())\n    };\n\n    // Do not support call `api` asynchronously without dataIndexInside input.\n    var currDataIndexInside;\n    var currDirty = true;\n    var currItemModel;\n    var currLabelNormalModel;\n    var currLabelEmphasisModel;\n    var currVisualColor;\n\n    return function (dataIndexInside, payload) {\n        currDataIndexInside = dataIndexInside;\n        currDirty = true;\n\n        return renderItem && renderItem(\n            defaults({\n                dataIndexInside: dataIndexInside,\n                dataIndex: data.getRawIndex(dataIndexInside),\n                // Can be used for optimization when zoom or roam.\n                actionType: payload ? payload.type : null\n            }, userParams),\n            userAPI\n        );\n    };\n\n    // Do not update cache until api called.\n    function updateCache(dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        if (currDirty) {\n            currItemModel = data.getItemModel(dataIndexInside);\n            currLabelNormalModel = currItemModel.getModel(LABEL_NORMAL);\n            currLabelEmphasisModel = currItemModel.getModel(LABEL_EMPHASIS);\n            currVisualColor = data.getItemVisual(dataIndexInside, 'color');\n\n            currDirty = false;\n        }\n    }\n\n    /**\n     * @public\n     * @param {number|string} dim\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     * @return {number|string} value\n     */\n    function value(dim, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        return data.get(data.getDimension(dim || 0), dataIndexInside);\n    }\n\n    /**\n     * By default, `visual` is applied to style (to support visualMap).\n     * `visual.color` is applied at `fill`. If user want apply visual.color on `stroke`,\n     * it can be implemented as:\n     * `api.style({stroke: api.visual('color'), fill: null})`;\n     * @public\n     * @param {Object} [extra]\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function style(extra, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        updateCache(dataIndexInside);\n\n        var itemStyle = currItemModel.getModel(ITEM_STYLE_NORMAL_PATH).getItemStyle();\n\n        currVisualColor != null && (itemStyle.fill = currVisualColor);\n        var opacity = data.getItemVisual(dataIndexInside, 'opacity');\n        opacity != null && (itemStyle.opacity = opacity);\n\n        setTextStyle(itemStyle, currLabelNormalModel, null, {\n            autoColor: currVisualColor,\n            isRectText: true\n        });\n\n        itemStyle.text = currLabelNormalModel.getShallow('show')\n            ? retrieve2(\n                customSeries.getFormattedLabel(dataIndexInside, 'normal'),\n                getDefaultLabel(data, dataIndexInside)\n            )\n            : null;\n\n        extra && extend(itemStyle, extra);\n        return itemStyle;\n    }\n\n    /**\n     * @public\n     * @param {Object} [extra]\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function styleEmphasis(extra, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        updateCache(dataIndexInside);\n\n        var itemStyle = currItemModel.getModel(ITEM_STYLE_EMPHASIS_PATH).getItemStyle();\n\n        setTextStyle(itemStyle, currLabelEmphasisModel, null, {\n            isRectText: true\n        }, true);\n\n        itemStyle.text = currLabelEmphasisModel.getShallow('show')\n            ? retrieve3(\n                customSeries.getFormattedLabel(dataIndexInside, 'emphasis'),\n                customSeries.getFormattedLabel(dataIndexInside, 'normal'),\n                getDefaultLabel(data, dataIndexInside)\n            )\n            : null;\n\n        extra && extend(itemStyle, extra);\n        return itemStyle;\n    }\n\n    /**\n     * @public\n     * @param {string} visualType\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function visual(visualType, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        return data.getItemVisual(dataIndexInside, visualType);\n    }\n\n    /**\n     * @public\n     * @param {number} opt.count Positive interger.\n     * @param {number} [opt.barWidth]\n     * @param {number} [opt.barMaxWidth]\n     * @param {number} [opt.barGap]\n     * @param {number} [opt.barCategoryGap]\n     * @return {Object} {width, offset, offsetCenter} is not support, return undefined.\n     */\n    function barLayout(opt) {\n        if (coordSys.getBaseAxis) {\n            var baseAxis = coordSys.getBaseAxis();\n            return getLayoutOnAxis(defaults({axis: baseAxis}, opt), api);\n        }\n    }\n\n    /**\n     * @public\n     * @return {Array.<number>}\n     */\n    function currentSeriesIndices() {\n        return ecModel.getCurrentSeriesIndices();\n    }\n\n    /**\n     * @public\n     * @param {Object} opt\n     * @param {string} [opt.fontStyle]\n     * @param {number} [opt.fontWeight]\n     * @param {number} [opt.fontSize]\n     * @param {string} [opt.fontFamily]\n     * @return {string} font string\n     */\n    function font(opt) {\n        return getFont(opt, ecModel);\n    }\n}\n\nfunction wrapEncodeDef(data) {\n    var encodeDef = {};\n    each$1(data.dimensions, function (dimName, dataDimIndex) {\n        var dimInfo = data.getDimensionInfo(dimName);\n        if (!dimInfo.isExtraCoord) {\n            var coordDim = dimInfo.coordDim;\n            var dataDims = encodeDef[coordDim] = encodeDef[coordDim] || [];\n            dataDims[dimInfo.coordDimIndex] = dataDimIndex;\n        }\n    });\n    return encodeDef;\n}\n\nfunction createOrUpdate$1(el, dataIndex, elOption, animatableModel, group, data) {\n    el = doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data, true);\n    el && data.setItemGraphicEl(dataIndex, el);\n\n    return el;\n}\n\nfunction doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data, isRoot) {\n\n    // [Rule]\n    // By default, follow merge mode.\n    //     (It probably brings benifit for performance in some cases of large data, where\n    //     user program can be optimized to that only updated props needed to be re-calculated,\n    //     or according to `actionType` some calculation can be skipped.)\n    // If `renderItem` returns `null`/`undefined`/`false`, remove the previous el if existing.\n    //     (It seems that violate the \"merge\" principle, but most of users probably intuitively\n    //     regard \"return;\" as \"show nothing element whatever\", so make a exception to meet the\n    //     most cases.)\n\n    var simplyRemove = !elOption; // `null`/`undefined`/`false`\n    elOption = elOption || {};\n    var elOptionType = elOption.type;\n    var elOptionShape = elOption.shape;\n    var elOptionStyle = elOption.style;\n\n    if (el && (\n        simplyRemove\n        // || elOption.$merge === false\n        // If `elOptionType` is `null`, follow the merge principle.\n        || (elOptionType != null\n            && elOptionType !== el.__customGraphicType\n        )\n        || (elOptionType === 'path'\n            && hasOwnPathData(elOptionShape) && getPathData(elOptionShape) !== el.__customPathData\n        )\n        || (elOptionType === 'image'\n            && hasOwn(elOptionStyle, 'image') && elOptionStyle.image !== el.__customImagePath\n        )\n        // FIXME test and remove this restriction?\n        || (elOptionType === 'text'\n            && hasOwn(elOptionShape, 'text') && elOptionStyle.text !== el.__customText\n        )\n    )) {\n        group.remove(el);\n        el = null;\n    }\n\n    // `elOption.type` is undefined when `renderItem` returns nothing.\n    if (simplyRemove) {\n        return;\n    }\n\n    var isInit = !el;\n    !el && (el = createEl(elOption));\n    updateEl(el, dataIndex, elOption, animatableModel, data, isInit, isRoot);\n\n    if (elOptionType === 'group') {\n        mergeChildren(el, dataIndex, elOption, animatableModel, data);\n    }\n\n    // Always add whatever already added to ensure sequence.\n    group.add(el);\n\n    return el;\n}\n\n// Usage:\n// (1) By default, `elOption.$mergeChildren` is `'byIndex'`, which indicates that\n//     the existing children will not be removed, and enables the feature that\n//     update some of the props of some of the children simply by construct\n//     the returned children of `renderItem` like:\n//     `var children = group.children = []; children[3] = {opacity: 0.5};`\n// (2) If `elOption.$mergeChildren` is `'byName'`, add/update/remove children\n//     by child.name. But that might be lower performance.\n// (3) If `elOption.$mergeChildren` is `false`, the existing children will be\n//     replaced totally.\n// (4) If `!elOption.children`, following the \"merge\" principle, nothing will happen.\n//\n// For implementation simpleness, do not provide a direct way to remove sinlge\n// child (otherwise the total indicies of the children array have to be modified).\n// User can remove a single child by set its `ignore` as `true` or replace\n// it by another element, where its `$merge` can be set as `true` if necessary.\nfunction mergeChildren(el, dataIndex, elOption, animatableModel, data) {\n    var newChildren = elOption.children;\n    var newLen = newChildren ? newChildren.length : 0;\n    var mergeChildren = elOption.$mergeChildren;\n    // `diffChildrenByName` has been deprecated.\n    var byName = mergeChildren === 'byName' || elOption.diffChildrenByName;\n    var notMerge = mergeChildren === false;\n\n    // For better performance on roam update, only enter if necessary.\n    if (!newLen && !byName && !notMerge) {\n        return;\n    }\n\n    if (byName) {\n        diffGroupChildren({\n            oldChildren: el.children() || [],\n            newChildren: newChildren || [],\n            dataIndex: dataIndex,\n            animatableModel: animatableModel,\n            group: el,\n            data: data\n        });\n        return;\n    }\n\n    notMerge && el.removeAll();\n\n    // Mapping children of a group simply by index, which\n    // might be better performance.\n    var index = 0;\n    for (; index < newLen; index++) {\n        newChildren[index] && doCreateOrUpdate(\n            el.childAt(index),\n            dataIndex,\n            newChildren[index],\n            animatableModel,\n            el,\n            data\n        );\n    }\n    if (__DEV__) {\n        assert$1(\n            !notMerge || el.childCount() === index,\n            'MUST NOT contain empty item in children array when `group.$mergeChildren` is `false`.'\n        );\n    }\n}\n\nfunction diffGroupChildren(context) {\n    (new DataDiffer(\n        context.oldChildren,\n        context.newChildren,\n        getKey,\n        getKey,\n        context\n    ))\n        .add(processAddUpdate)\n        .update(processAddUpdate)\n        .remove(processRemove)\n        .execute();\n}\n\nfunction getKey(item, idx) {\n    var name = item && item.name;\n    return name != null ? name : GROUP_DIFF_PREFIX + idx;\n}\n\nfunction processAddUpdate(newIndex, oldIndex) {\n    var context = this.context;\n    var childOption = newIndex != null ? context.newChildren[newIndex] : null;\n    var child = oldIndex != null ? context.oldChildren[oldIndex] : null;\n\n    doCreateOrUpdate(\n        child,\n        context.dataIndex,\n        childOption,\n        context.animatableModel,\n        context.group,\n        context.data\n    );\n}\n\nfunction processRemove(oldIndex) {\n    var context = this.context;\n    var child = context.oldChildren[oldIndex];\n    child && context.group.remove(child);\n}\n\nfunction getPathData(shape) {\n    // \"d\" follows the SVG convention.\n    return shape && (shape.pathData || shape.d);\n}\n\nfunction hasOwnPathData(shape) {\n    return shape && (shape.hasOwnProperty('pathData') || shape.hasOwnProperty('d'));\n}\n\nfunction hasOwn(host, prop) {\n    return host && host.hasOwnProperty(prop);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// -------------\n// Preprocessor\n// -------------\n\nregisterPreprocessor(function (option) {\n    var graphicOption = option.graphic;\n\n    // Convert\n    // {graphic: [{left: 10, type: 'circle'}, ...]}\n    // or\n    // {graphic: {left: 10, type: 'circle'}}\n    // to\n    // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]}\n    if (isArray(graphicOption)) {\n        if (!graphicOption[0] || !graphicOption[0].elements) {\n            option.graphic = [{elements: graphicOption}];\n        }\n        else {\n            // Only one graphic instance can be instantiated. (We dont\n            // want that too many views are created in echarts._viewMap)\n            option.graphic = [option.graphic[0]];\n        }\n    }\n    else if (graphicOption && !graphicOption.elements) {\n        option.graphic = [{elements: [graphicOption]}];\n    }\n});\n\n// ------\n// Model\n// ------\n\nvar GraphicModel = extendComponentModel({\n\n    type: 'graphic',\n\n    defaultOption: {\n\n        // Extra properties for each elements:\n        //\n        // left/right/top/bottom: (like 12, '22%', 'center', default undefined)\n        //      If left/rigth is set, shape.x/shape.cx/position will not be used.\n        //      If top/bottom is set, shape.y/shape.cy/position will not be used.\n        //      This mechanism is useful when you want to position a group/element\n        //      against the right side or the center of this container.\n        //\n        // width/height: (can only be pixel value, default 0)\n        //      Only be used to specify contianer(group) size, if needed. And\n        //      can not be percentage value (like '33%'). See the reason in the\n        //      layout algorithm below.\n        //\n        // bounding: (enum: 'all' (default) | 'raw')\n        //      Specify how to calculate boundingRect when locating.\n        //      'all': Get uioned and transformed boundingRect\n        //          from both itself and its descendants.\n        //          This mode simplies confining a group of elements in the bounding\n        //          of their ancester container (e.g., using 'right: 0').\n        //      'raw': Only use the boundingRect of itself and before transformed.\n        //          This mode is similar to css behavior, which is useful when you\n        //          want an element to be able to overflow its container. (Consider\n        //          a rotated circle needs to be located in a corner.)\n        // info: custom info. enables user to mount some info on elements and use them\n        //      in event handlers. Update them only when user specified, otherwise, remain.\n\n        // Note: elements is always behind its ancestors in this elements array.\n        elements: [],\n        parentId: null\n    },\n\n    /**\n     * Save el options for the sake of the performance (only update modified graphics).\n     * The order is the same as those in option. (ancesters -> descendants)\n     *\n     * @private\n     * @type {Array.<Object>}\n     */\n    _elOptionsToUpdate: null,\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        // Prevent default merge to elements\n        var elements = this.option.elements;\n        this.option.elements = null;\n\n        GraphicModel.superApply(this, 'mergeOption', arguments);\n\n        this.option.elements = elements;\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n        var newList = (isInit ? thisOption : newOption).elements;\n        var existList = thisOption.elements = isInit ? [] : thisOption.elements;\n\n        var flattenedList = [];\n        this._flatten(newList, flattenedList);\n\n        var mappingResult = mappingToExists(existList, flattenedList);\n        makeIdAndName(mappingResult);\n\n        // Clear elOptionsToUpdate\n        var elOptionsToUpdate = this._elOptionsToUpdate = [];\n\n        each$1(mappingResult, function (resultItem, index) {\n            var newElOption = resultItem.option;\n\n            if (__DEV__) {\n                assert$1(\n                    isObject$1(newElOption) || resultItem.exist,\n                    'Empty graphic option definition'\n                );\n            }\n\n            if (!newElOption) {\n                return;\n            }\n\n            elOptionsToUpdate.push(newElOption);\n\n            setKeyInfoToNewElOption(resultItem, newElOption);\n\n            mergeNewElOptionToExist(existList, index, newElOption);\n\n            setLayoutInfoToExist(existList[index], newElOption);\n\n        }, this);\n\n        // Clean\n        for (var i = existList.length - 1; i >= 0; i--) {\n            if (existList[i] == null) {\n                existList.splice(i, 1);\n            }\n            else {\n                // $action should be volatile, otherwise option gotten from\n                // `getOption` will contain unexpected $action.\n                delete existList[i].$action;\n            }\n        }\n    },\n\n    /**\n     * Convert\n     * [{\n     *  type: 'group',\n     *  id: 'xx',\n     *  children: [{type: 'circle'}, {type: 'polygon'}]\n     * }]\n     * to\n     * [\n     *  {type: 'group', id: 'xx'},\n     *  {type: 'circle', parentId: 'xx'},\n     *  {type: 'polygon', parentId: 'xx'}\n     * ]\n     *\n     * @private\n     * @param {Array.<Object>} optionList option list\n     * @param {Array.<Object>} result result of flatten\n     * @param {Object} parentOption parent option\n     */\n    _flatten: function (optionList, result, parentOption) {\n        each$1(optionList, function (option) {\n            if (!option) {\n                return;\n            }\n\n            if (parentOption) {\n                option.parentOption = parentOption;\n            }\n\n            result.push(option);\n\n            var children = option.children;\n            if (option.type === 'group' && children) {\n                this._flatten(children, result, option);\n            }\n            // Deleting for JSON output, and for not affecting group creation.\n            delete option.children;\n        }, this);\n    },\n\n    // FIXME\n    // Pass to view using payload? setOption has a payload?\n    useElOptionsToUpdate: function () {\n        var els = this._elOptionsToUpdate;\n        // Clear to avoid render duplicately when zooming.\n        this._elOptionsToUpdate = null;\n        return els;\n    }\n});\n\n// -----\n// View\n// -----\n\nextendComponentView({\n\n    type: 'graphic',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this._elMap = createHashMap();\n\n        /**\n         * @private\n         * @type {module:echarts/graphic/GraphicModel}\n         */\n        this._lastGraphicModel;\n    },\n\n    /**\n     * @override\n     */\n    render: function (graphicModel, ecModel, api) {\n\n        // Having leveraged between use cases and algorithm complexity, a very\n        // simple layout mechanism is used:\n        // The size(width/height) can be determined by itself or its parent (not\n        // implemented yet), but can not by its children. (Top-down travel)\n        // The location(x/y) can be determined by the bounding rect of itself\n        // (can including its descendants or not) and the size of its parent.\n        // (Bottom-up travel)\n\n        // When `chart.clear()` or `chart.setOption({...}, true)` with the same id,\n        // view will be reused.\n        if (graphicModel !== this._lastGraphicModel) {\n            this._clear();\n        }\n        this._lastGraphicModel = graphicModel;\n\n        this._updateElements(graphicModel);\n        this._relocate(graphicModel, api);\n    },\n\n    /**\n     * Update graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     */\n    _updateElements: function (graphicModel) {\n        var elOptionsToUpdate = graphicModel.useElOptionsToUpdate();\n\n        if (!elOptionsToUpdate) {\n            return;\n        }\n\n        var elMap = this._elMap;\n        var rootGroup = this.group;\n\n        // Top-down tranverse to assign graphic settings to each elements.\n        each$1(elOptionsToUpdate, function (elOption) {\n            var $action = elOption.$action;\n            var id = elOption.id;\n            var existEl = elMap.get(id);\n            var parentId = elOption.parentId;\n            var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup;\n\n            var elOptionStyle = elOption.style;\n            if (elOption.type === 'text' && elOptionStyle) {\n                // In top/bottom mode, textVerticalAlign should not be used, which cause\n                // inaccurately locating.\n                if (elOption.hv && elOption.hv[1]) {\n                    elOptionStyle.textVerticalAlign = elOptionStyle.textBaseline = null;\n                }\n\n                // Compatible with previous setting: both support fill and textFill,\n                // stroke and textStroke.\n                !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n                    elOptionStyle.textFill = elOptionStyle.fill\n                );\n                !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n                    elOptionStyle.textStroke = elOptionStyle.stroke\n                );\n            }\n\n            // Remove unnecessary props to avoid potential problems.\n            var elOptionCleaned = getCleanedElOption(elOption);\n\n            // For simple, do not support parent change, otherwise reorder is needed.\n            if (__DEV__) {\n                existEl && assert$1(\n                    targetElParent === existEl.parent,\n                    'Changing parent is not supported.'\n                );\n            }\n\n            if (!$action || $action === 'merge') {\n                existEl\n                    ? existEl.attr(elOptionCleaned)\n                    : createEl$1(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'replace') {\n                removeEl(existEl, elMap);\n                createEl$1(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'remove') {\n                removeEl(existEl, elMap);\n            }\n\n            var el = elMap.get(id);\n            if (el) {\n                el.__ecGraphicWidth = elOption.width;\n                el.__ecGraphicHeight = elOption.height;\n                setEventData(el, graphicModel, elOption);\n            }\n        });\n    },\n\n    /**\n     * Locate graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     * @param {module:echarts/ExtensionAPI} api extension API\n     */\n    _relocate: function (graphicModel, api) {\n        var elOptions = graphicModel.option.elements;\n        var rootGroup = this.group;\n        var elMap = this._elMap;\n\n        // Bottom-up tranvese all elements (consider ec resize) to locate elements.\n        for (var i = elOptions.length - 1; i >= 0; i--) {\n            var elOption = elOptions[i];\n            var el = elMap.get(elOption.id);\n\n            if (!el) {\n                continue;\n            }\n\n            var parentEl = el.parent;\n            var containerInfo = parentEl === rootGroup\n                ? {\n                    width: api.getWidth(),\n                    height: api.getHeight()\n                }\n                : { // Like 'position:absolut' in css, default 0.\n                    width: parentEl.__ecGraphicWidth || 0,\n                    height: parentEl.__ecGraphicHeight || 0\n                };\n\n            positionElement(\n                el, elOption, containerInfo, null,\n                {hv: elOption.hv, boundingMode: elOption.bounding}\n            );\n        }\n    },\n\n    /**\n     * Clear all elements.\n     *\n     * @private\n     */\n    _clear: function () {\n        var elMap = this._elMap;\n        elMap.each(function (el) {\n            removeEl(el, elMap);\n        });\n        this._elMap = createHashMap();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clear();\n    }\n});\n\nfunction createEl$1(id, targetElParent, elOption, elMap) {\n    var graphicType = elOption.type;\n\n    if (__DEV__) {\n        assert$1(graphicType, 'graphic type MUST be set');\n    }\n\n    var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n    if (__DEV__) {\n        assert$1(Clz, 'graphic type can not be found');\n    }\n\n    var el = new Clz(elOption);\n    targetElParent.add(el);\n    elMap.set(id, el);\n    el.__ecGraphicId = id;\n}\n\nfunction removeEl(existEl, elMap) {\n    var existElParent = existEl && existEl.parent;\n    if (existElParent) {\n        existEl.type === 'group' && existEl.traverse(function (el) {\n            removeEl(el, elMap);\n        });\n        elMap.removeKey(existEl.__ecGraphicId);\n        existElParent.remove(existEl);\n    }\n}\n\n// Remove unnecessary props to avoid potential problems.\nfunction getCleanedElOption(elOption) {\n    elOption = extend({}, elOption);\n    each$1(\n        ['id', 'parentId', '$action', 'hv', 'bounding'].concat(LOCATION_PARAMS),\n        function (name) {\n            delete elOption[name];\n        }\n    );\n    return elOption;\n}\n\nfunction isSetLoc(obj, props) {\n    var isSet;\n    each$1(props, function (prop) {\n        obj[prop] != null && obj[prop] !== 'auto' && (isSet = true);\n    });\n    return isSet;\n}\n\nfunction setKeyInfoToNewElOption(resultItem, newElOption) {\n    var existElOption = resultItem.exist;\n\n    // Set id and type after id assigned.\n    newElOption.id = resultItem.keyInfo.id;\n    !newElOption.type && existElOption && (newElOption.type = existElOption.type);\n\n    // Set parent id if not specified\n    if (newElOption.parentId == null) {\n        var newElParentOption = newElOption.parentOption;\n        if (newElParentOption) {\n            newElOption.parentId = newElParentOption.id;\n        }\n        else if (existElOption) {\n            newElOption.parentId = existElOption.parentId;\n        }\n    }\n\n    // Clear\n    newElOption.parentOption = null;\n}\n\nfunction mergeNewElOptionToExist(existList, index, newElOption) {\n    // Update existing options, for `getOption` feature.\n    var newElOptCopy = extend({}, newElOption);\n    var existElOption = existList[index];\n\n    var $action = newElOption.$action || 'merge';\n    if ($action === 'merge') {\n        if (existElOption) {\n\n            if (__DEV__) {\n                var newType = newElOption.type;\n                assert$1(\n                    !newType || existElOption.type === newType,\n                    'Please set $action: \"replace\" to change `type`'\n                );\n            }\n\n            // We can ensure that newElOptCopy and existElOption are not\n            // the same object, so `merge` will not change newElOptCopy.\n            merge(existElOption, newElOptCopy, true);\n            // Rigid body, use ignoreSize.\n            mergeLayoutParam(existElOption, newElOptCopy, {ignoreSize: true});\n            // Will be used in render.\n            copyLayoutParams(newElOption, existElOption);\n        }\n        else {\n            existList[index] = newElOptCopy;\n        }\n    }\n    else if ($action === 'replace') {\n        existList[index] = newElOptCopy;\n    }\n    else if ($action === 'remove') {\n        // null will be cleaned later.\n        existElOption && (existList[index] = null);\n    }\n}\n\nfunction setLayoutInfoToExist(existItem, newElOption) {\n    if (!existItem) {\n        return;\n    }\n    existItem.hv = newElOption.hv = [\n        // Rigid body, dont care `width`.\n        isSetLoc(newElOption, ['left', 'right']),\n        // Rigid body, dont care `height`.\n        isSetLoc(newElOption, ['top', 'bottom'])\n    ];\n    // Give default group size. Otherwise layout error may occur.\n    if (existItem.type === 'group') {\n        existItem.width == null && (existItem.width = newElOption.width = 0);\n        existItem.height == null && (existItem.height = newElOption.height = 0);\n    }\n}\n\nfunction setEventData(el, graphicModel, elOption) {\n    var eventData = el.eventData;\n    // Simple optimize for large amount of elements that no need event.\n    if (!el.silent && !el.ignore && !eventData) {\n        eventData = el.eventData = {\n            componentType: 'graphic',\n            componentIndex: graphicModel.componentIndex,\n            name: el.name\n        };\n    }\n\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    if (eventData) {\n        eventData.info = el.info;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar LegendModel = extendComponentModel({\n\n    type: 'legend.plain',\n\n    dependencies: ['series'],\n\n    layoutMode: {\n        type: 'box',\n        // legend.width/height are maxWidth/maxHeight actually,\n        // whereas realy width/height is calculated by its content.\n        // (Setting {left: 10, right: 10} does not make sense).\n        // So consider the case:\n        // `setOption({legend: {left: 10});`\n        // then `setOption({legend: {right: 10});`\n        // The previous `left` should be cleared by setting `ignoreSize`.\n        ignoreSize: true\n    },\n\n    init: function (option, parentModel, ecModel) {\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        option.selected = option.selected || {};\n    },\n\n    mergeOption: function (option) {\n        LegendModel.superCall(this, 'mergeOption', option);\n    },\n\n    optionUpdated: function () {\n        this._updateData(this.ecModel);\n\n        var legendData = this._data;\n\n        // If selectedMode is single, try to select one\n        if (legendData[0] && this.get('selectedMode') === 'single') {\n            var hasSelected = false;\n            // If has any selected in option.selected\n            for (var i = 0; i < legendData.length; i++) {\n                var name = legendData[i].get('name');\n                if (this.isSelected(name)) {\n                    // Force to unselect others\n                    this.select(name);\n                    hasSelected = true;\n                    break;\n                }\n            }\n            // Try select the first if selectedMode is single\n            !hasSelected && this.select(legendData[0].get('name'));\n        }\n    },\n\n    _updateData: function (ecModel) {\n        var potentialData = [];\n        var availableNames = [];\n\n        ecModel.eachRawSeries(function (seriesModel) {\n            var seriesName = seriesModel.name;\n            availableNames.push(seriesName);\n            var isPotential;\n\n            if (seriesModel.legendDataProvider) {\n                var data = seriesModel.legendDataProvider();\n                var names = data.mapArray(data.getName);\n\n                if (!ecModel.isSeriesFiltered(seriesModel)) {\n                    availableNames = availableNames.concat(names);\n                }\n\n                if (names.length) {\n                    potentialData = potentialData.concat(names);\n                }\n                else {\n                    isPotential = true;\n                }\n            }\n            else {\n                isPotential = true;\n            }\n\n            if (isPotential && isNameSpecified(seriesModel)) {\n                potentialData.push(seriesModel.name);\n            }\n        });\n\n        /**\n         * @type {Array.<string>}\n         * @private\n         */\n        this._availableNames = availableNames;\n\n        // If legend.data not specified in option, use availableNames as data,\n        // which is convinient for user preparing option.\n        var rawData = this.get('data') || potentialData;\n\n        var legendData = map(rawData, function (dataItem) {\n            // Can be string or number\n            if (typeof dataItem === 'string' || typeof dataItem === 'number') {\n                dataItem = {\n                    name: dataItem\n                };\n            }\n            return new Model(dataItem, this, this.ecModel);\n        }, this);\n\n        /**\n         * @type {Array.<module:echarts/model/Model>}\n         * @private\n         */\n        this._data = legendData;\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Model>}\n     */\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @param {string} name\n     */\n    select: function (name) {\n        var selected = this.option.selected;\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            var data = this._data;\n            each$1(data, function (dataItem) {\n                selected[dataItem.get('name')] = false;\n            });\n        }\n        selected[name] = true;\n    },\n\n    /**\n     * @param {string} name\n     */\n    unSelect: function (name) {\n        if (this.get('selectedMode') !== 'single') {\n            this.option.selected[name] = false;\n        }\n    },\n\n    /**\n     * @param {string} name\n     */\n    toggleSelected: function (name) {\n        var selected = this.option.selected;\n        // Default is true\n        if (!selected.hasOwnProperty(name)) {\n            selected[name] = true;\n        }\n        this[selected[name] ? 'unSelect' : 'select'](name);\n    },\n\n    /**\n     * @param {string} name\n     */\n    isSelected: function (name) {\n        var selected = this.option.selected;\n        return !(selected.hasOwnProperty(name) && !selected[name])\n            && indexOf(this._availableNames, name) >= 0;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 4,\n        show: true,\n\n        // 布局方式，默认为水平布局，可选为：\n        // 'horizontal' | 'vertical'\n        orient: 'horizontal',\n\n        left: 'center',\n        // right: 'center',\n\n        top: 0,\n        // bottom: null,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right'\n        // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐\n        align: 'auto',\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        // 图例边框颜色\n        borderColor: '#ccc',\n        borderRadius: 0,\n        // 图例边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n        // 图例内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n        // 各个item之间的间隔，单位px，默认为10，\n        // 横向布局时为水平间隔，纵向布局时为纵向间隔\n        itemGap: 10,\n        // 图例图形宽度\n        itemWidth: 25,\n        // 图例图形高度\n        itemHeight: 14,\n\n        // 图例关闭时候的颜色\n        inactiveColor: '#ccc',\n\n        textStyle: {\n            // 图例文字颜色\n            color: '#333'\n        },\n        // formatter: '',\n        // 选择模式，默认开启图例开关\n        selectedMode: true,\n        // 配置默认选中状态，可配合LEGEND.SELECTED事件做动态数据载入\n        // selected: null,\n        // 图例内容（详见legend.data，数组中每一项代表一个item\n        // data: [],\n\n        // Tooltip 相关配置\n        tooltip: {\n            show: false\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction legendSelectActionHandler(methodName, payload, ecModel) {\n    var selectedMap = {};\n    var isToggleSelect = methodName === 'toggleSelected';\n    var isSelected;\n    // Update all legend components\n    ecModel.eachComponent('legend', function (legendModel) {\n        if (isToggleSelect && isSelected != null) {\n            // Force other legend has same selected status\n            // Or the first is toggled to true and other are toggled to false\n            // In the case one legend has some item unSelected in option. And if other legend\n            // doesn't has the item, they will assume it is selected.\n            legendModel[isSelected ? 'select' : 'unSelect'](payload.name);\n        }\n        else {\n            legendModel[methodName](payload.name);\n            isSelected = legendModel.isSelected(payload.name);\n        }\n        var legendData = legendModel.getData();\n        each$1(legendData, function (model) {\n            var name = model.get('name');\n            // Wrap element\n            if (name === '\\n' || name === '') {\n                return;\n            }\n            var isItemSelected = legendModel.isSelected(name);\n            if (selectedMap.hasOwnProperty(name)) {\n                // Unselected if any legend is unselected\n                selectedMap[name] = selectedMap[name] && isItemSelected;\n            }\n            else {\n                selectedMap[name] = isItemSelected;\n            }\n        });\n    });\n    // Return the event explicitly\n    return {\n        name: payload.name,\n        selected: selectedMap\n    };\n}\n/**\n * @event legendToggleSelect\n * @type {Object}\n * @property {string} type 'legendToggleSelect'\n * @property {string} [from]\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendToggleSelect', 'legendselectchanged',\n    curry(legendSelectActionHandler, 'toggleSelected')\n);\n\n/**\n * @event legendSelect\n * @type {Object}\n * @property {string} type 'legendSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendSelect', 'legendselected',\n    curry(legendSelectActionHandler, 'select')\n);\n\n/**\n * @event legendUnSelect\n * @type {Object}\n * @property {string} type 'legendUnSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendUnSelect', 'legendunselected',\n    curry(legendSelectActionHandler, 'unSelect')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Layout list like component.\n * It will box layout each items in group of component and then position the whole group in the viewport\n * @param {module:zrender/group/Group} group\n * @param {module:echarts/model/Component} componentModel\n * @param {module:echarts/ExtensionAPI}\n */\nfunction layout$3(group, componentModel, api) {\n    var boxLayoutParams = componentModel.getBoxLayoutParams();\n    var padding = componentModel.get('padding');\n    var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n\n    var rect = getLayoutRect(\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n\n    box(\n        componentModel.get('orient'),\n        group,\n        componentModel.get('itemGap'),\n        rect.width,\n        rect.height\n    );\n\n    positionElement(\n        group,\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n}\n\nfunction makeBackground(rect, componentModel) {\n    var padding = normalizeCssArray$1(\n        componentModel.get('padding')\n    );\n    var style = componentModel.getItemStyle(['color', 'opacity']);\n    style.fill = componentModel.get('backgroundColor');\n    var rect = new Rect({\n        shape: {\n            x: rect.x - padding[3],\n            y: rect.y - padding[0],\n            width: rect.width + padding[1] + padding[3],\n            height: rect.height + padding[0] + padding[2],\n            r: componentModel.get('borderRadius')\n        },\n        style: style,\n        silent: true,\n        z2: -1\n    });\n    // FIXME\n    // `subPixelOptimizeRect` may bring some gap between edge of viewpart\n    // and background rect when setting like `left: 0`, `top: 0`.\n    // graphic.subPixelOptimizeRect(rect);\n\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$4 = curry;\nvar each$16 = each$1;\nvar Group$3 = Group;\n\nvar LegendView = extendComponentView({\n\n    type: 'legend.plain',\n\n    newlineDisabled: false,\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._contentGroup = new Group$3());\n\n        /**\n         * @private\n         * @type {module:zrender/Element}\n         */\n        this._backgroundEl;\n\n        /**\n         * If first rendering, `contentGroup.position` is [0, 0], which\n         * does not make sense and may cause unexepcted animation if adopted.\n         * @private\n         * @type {boolean}\n         */\n        this._isFirstRender = true;\n    },\n\n    /**\n     * @protected\n     */\n    getContentGroup: function () {\n        return this._contentGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (legendModel, ecModel, api) {\n        var isFirstRender = this._isFirstRender;\n        this._isFirstRender = false;\n\n        this.resetInner();\n\n        if (!legendModel.get('show', true)) {\n            return;\n        }\n\n        var itemAlign = legendModel.get('align');\n        if (!itemAlign || itemAlign === 'auto') {\n            itemAlign = (\n                legendModel.get('left') === 'right'\n                && legendModel.get('orient') === 'vertical'\n            ) ? 'right' : 'left';\n        }\n\n        this.renderInner(itemAlign, legendModel, ecModel, api);\n\n        // Perform layout.\n        var positionInfo = legendModel.getBoxLayoutParams();\n        var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n        var padding = legendModel.get('padding');\n\n        var maxSize = getLayoutRect(positionInfo, viewportSize, padding);\n\n        var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender);\n\n        // Place mainGroup, based on the calculated `mainRect`.\n        var layoutRect = getLayoutRect(\n            defaults({width: mainRect.width, height: mainRect.height}, positionInfo),\n            viewportSize,\n            padding\n        );\n        this.group.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]);\n\n        // Render background after group is layout.\n        this.group.add(\n            this._backgroundEl = makeBackground(mainRect, legendModel)\n        );\n    },\n\n    /**\n     * @protected\n     */\n    resetInner: function () {\n        this.getContentGroup().removeAll();\n        this._backgroundEl && this.group.remove(this._backgroundEl);\n    },\n\n    /**\n     * @protected\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var contentGroup = this.getContentGroup();\n        var legendDrawnMap = createHashMap();\n        var selectMode = legendModel.get('selectedMode');\n\n        var excludeSeriesId = [];\n        ecModel.eachRawSeries(function (seriesModel) {\n            !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id);\n        });\n\n        each$16(legendModel.getData(), function (itemModel, dataIndex) {\n            var name = itemModel.get('name');\n\n            // Use empty string or \\n as a newline string\n            if (!this.newlineDisabled && (name === '' || name === '\\n')) {\n                contentGroup.add(new Group$3({\n                    newline: true\n                }));\n                return;\n            }\n\n            // Representitive series.\n            var seriesModel = ecModel.getSeriesByName(name)[0];\n\n            if (legendDrawnMap.get(name)) {\n                // Have been drawed\n                return;\n            }\n\n            // Series legend\n            if (seriesModel) {\n                var data = seriesModel.getData();\n                var color = data.getVisual('color');\n\n                // If color is a callback function\n                if (typeof color === 'function') {\n                    // Use the first data\n                    color = color(seriesModel.getDataParams(0));\n                }\n\n                // Using rect symbol defaultly\n                var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';\n                var symbolType = data.getVisual('symbol');\n\n                var itemGroup = this._createItem(\n                    name, dataIndex, itemModel, legendModel,\n                    legendSymbolType, symbolType,\n                    itemAlign, color,\n                    selectMode\n                );\n\n                itemGroup.on('click', curry$4(dispatchSelectAction, name, api))\n                    .on('mouseover', curry$4(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId))\n                    .on('mouseout', curry$4(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId));\n\n                legendDrawnMap.set(name, true);\n            }\n            else {\n                // Data legend of pie, funnel\n                ecModel.eachRawSeries(function (seriesModel) {\n                    // In case multiple series has same data name\n                    if (legendDrawnMap.get(name)) {\n                        return;\n                    }\n\n                    if (seriesModel.legendDataProvider) {\n                        var data = seriesModel.legendDataProvider();\n                        var idx = data.indexOfName(name);\n                        if (idx < 0) {\n                            return;\n                        }\n\n                        var color = data.getItemVisual(idx, 'color');\n\n                        var legendSymbolType = 'roundRect';\n\n                        var itemGroup = this._createItem(\n                            name, dataIndex, itemModel, legendModel,\n                            legendSymbolType, null,\n                            itemAlign, color,\n                            selectMode\n                        );\n\n                        // FIXME: consider different series has items with the same name.\n                        itemGroup.on('click', curry$4(dispatchSelectAction, name, api))\n                            // Should not specify the series name, consider legend controls\n                            // more than one pie series.\n                            .on('mouseover', curry$4(dispatchHighlightAction, null, name, api, excludeSeriesId))\n                            .on('mouseout', curry$4(dispatchDownplayAction, null, name, api, excludeSeriesId));\n\n                        legendDrawnMap.set(name, true);\n                    }\n\n                }, this);\n            }\n\n            if (__DEV__) {\n                if (!legendDrawnMap.get(name)) {\n                    console.warn(\n                        name + ' series not exists. Legend data should be same with series name or data name.'\n                    );\n                }\n            }\n        }, this);\n    },\n\n    _createItem: function (\n        name, dataIndex, itemModel, legendModel,\n        legendSymbolType, symbolType,\n        itemAlign, color, selectMode\n    ) {\n        var itemWidth = legendModel.get('itemWidth');\n        var itemHeight = legendModel.get('itemHeight');\n        var inactiveColor = legendModel.get('inactiveColor');\n        var symbolKeepAspect = legendModel.get('symbolKeepAspect');\n\n        var isSelected = legendModel.isSelected(name);\n        var itemGroup = new Group$3();\n\n        var textStyleModel = itemModel.getModel('textStyle');\n\n        var itemIcon = itemModel.get('icon');\n\n        var tooltipModel = itemModel.getModel('tooltip');\n        var legendGlobalTooltipModel = tooltipModel.parentModel;\n\n        // Use user given icon first\n        legendSymbolType = itemIcon || legendSymbolType;\n        itemGroup.add(createSymbol(\n            legendSymbolType,\n            0,\n            0,\n            itemWidth,\n            itemHeight,\n            isSelected ? color : inactiveColor,\n            // symbolKeepAspect default true for legend\n            symbolKeepAspect == null ? true : symbolKeepAspect\n        ));\n\n        // Compose symbols\n        // PENDING\n        if (!itemIcon && symbolType\n            // At least show one symbol, can't be all none\n            && ((symbolType !== legendSymbolType) || symbolType === 'none')\n        ) {\n            var size = itemHeight * 0.8;\n            if (symbolType === 'none') {\n                symbolType = 'circle';\n            }\n            // Put symbol in the center\n            itemGroup.add(createSymbol(\n                symbolType,\n                (itemWidth - size) / 2,\n                (itemHeight - size) / 2,\n                size,\n                size,\n                isSelected ? color : inactiveColor,\n                // symbolKeepAspect default true for legend\n                symbolKeepAspect == null ? true : symbolKeepAspect\n            ));\n        }\n\n        var textX = itemAlign === 'left' ? itemWidth + 5 : -5;\n        var textAlign = itemAlign;\n\n        var formatter = legendModel.get('formatter');\n        var content = name;\n        if (typeof formatter === 'string' && formatter) {\n            content = formatter.replace('{name}', name != null ? name : '');\n        }\n        else if (typeof formatter === 'function') {\n            content = formatter(name);\n        }\n\n        itemGroup.add(new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: content,\n                x: textX,\n                y: itemHeight / 2,\n                textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor,\n                textAlign: textAlign,\n                textVerticalAlign: 'middle'\n            })\n        }));\n\n        // Add a invisible rect to increase the area of mouse hover\n        var hitRect = new Rect({\n            shape: itemGroup.getBoundingRect(),\n            invisible: true,\n            tooltip: tooltipModel.get('show') ? extend({\n                content: name,\n                // Defaul formatter\n                formatter: legendGlobalTooltipModel.get('formatter', true) || function () {\n                    return name;\n                },\n                formatterParams: {\n                    componentType: 'legend',\n                    legendIndex: legendModel.componentIndex,\n                    name: name,\n                    $vars: ['name']\n                }\n            }, tooltipModel.option) : null\n        });\n        itemGroup.add(hitRect);\n\n        itemGroup.eachChild(function (child) {\n            child.silent = true;\n        });\n\n        hitRect.silent = !selectMode;\n\n        this.getContentGroup().add(itemGroup);\n\n        setHoverStyle(itemGroup);\n\n        itemGroup.__legendDataIndex = dataIndex;\n\n        return itemGroup;\n    },\n\n    /**\n     * @protected\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize) {\n        var contentGroup = this.getContentGroup();\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            maxSize.width,\n            maxSize.height\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        contentGroup.attr('position', [-contentRect.x, -contentRect.y]);\n\n        return this.group.getBoundingRect();\n    },\n\n    /**\n     * @protected\n     */\n    remove: function () {\n        this.getContentGroup().removeAll();\n        this._isFirstRender = true;\n    }\n\n});\n\nfunction dispatchSelectAction(name, api) {\n    api.dispatchAction({\n        type: 'legendToggleSelect',\n        name: name\n    });\n}\n\nfunction dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'highlight',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\nfunction dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'downplay',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar legendFilter = function (ecModel) {\n\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (legendModels && legendModels.length) {\n        ecModel.filterSeries(function (series) {\n            // If in any legend component the status is not selected.\n            // Because in legend series is assumed selected when it is not in the legend data.\n            for (var i = 0; i < legendModels.length; i++) {\n                if (!legendModels[i].isSelected(series.name)) {\n                    return false;\n                }\n            }\n            return true;\n        });\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Do not contain scrollable legend, for sake of file size.\n\n// Series Filter\nregisterProcessor(legendFilter);\n\nComponentModel.registerSubTypeDefaulter('legend', function () {\n    // Default 'plain' when no type specified.\n    return 'plain';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ScrollableLegendModel = LegendModel.extend({\n\n    type: 'legend.scroll',\n\n    /**\n     * @param {number} scrollDataIndex\n     */\n    setScrollDataIndex: function (scrollDataIndex) {\n        this.option.scrollDataIndex = scrollDataIndex;\n    },\n\n    defaultOption: {\n        scrollDataIndex: 0,\n        pageButtonItemGap: 5,\n        pageButtonGap: null,\n        pageButtonPosition: 'end', // 'start' or 'end'\n        pageFormatter: '{current}/{total}', // If null/undefined, do not show page.\n        pageIcons: {\n            horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'],\n            vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z']\n        },\n        pageIconColor: '#2f4554',\n        pageIconInactiveColor: '#aaa',\n        pageIconSize: 15, // Can be [10, 3], which represents [width, height]\n        pageTextStyle: {\n            color: '#333'\n        },\n\n        animationDurationUpdate: 800\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        ScrollableLegendModel.superCall(this, 'init', option, parentModel, ecModel, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, this.option, option);\n    },\n\n    getOrient: function () {\n        return this.get('orient') === 'vertical'\n            ? {index: 1, name: 'vertical'}\n            : {index: 0, name: 'horizontal'};\n    }\n\n});\n\n// Do not `ignoreSize` to enable setting {left: 10, right: 10}.\nfunction mergeAndNormalizeLayoutParams(legendModel, target, raw) {\n    var orient = legendModel.getOrient();\n    var ignoreSize = [1, 1];\n    ignoreSize[orient.index] = 0;\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Separate legend and scrollable legend to reduce package size.\n */\n\nvar Group$4 = Group;\n\nvar WH$1 = ['width', 'height'];\nvar XY$1 = ['x', 'y'];\n\nvar ScrollableLegendView = LegendView.extend({\n\n    type: 'legend.scroll',\n\n    newlineDisabled: true,\n\n    init: function () {\n\n        ScrollableLegendView.superCall(this, 'init');\n\n        /**\n         * @private\n         * @type {number} For `scroll`.\n         */\n        this._currentIndex = 0;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._containerGroup = new Group$4());\n        this._containerGroup.add(this.getContentGroup());\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._controllerGroup = new Group$4());\n\n        /**\n         *\n         * @private\n         */\n        this._showController;\n    },\n\n    /**\n     * @override\n     */\n    resetInner: function () {\n        ScrollableLegendView.superCall(this, 'resetInner');\n\n        this._controllerGroup.removeAll();\n        this._containerGroup.removeClipPath();\n        this._containerGroup.__rectSize = null;\n    },\n\n    /**\n     * @override\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var me = this;\n\n        // Render content items.\n        ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api);\n\n        var controllerGroup = this._controllerGroup;\n\n        // FIXME: support be 'auto' adapt to size number text length,\n        // e.g., '3/12345' should not overlap with the control arrow button.\n        var pageIconSize = legendModel.get('pageIconSize', true);\n        if (!isArray(pageIconSize)) {\n            pageIconSize = [pageIconSize, pageIconSize];\n        }\n\n        createPageButton('pagePrev', 0);\n\n        var pageTextStyleModel = legendModel.getModel('pageTextStyle');\n        controllerGroup.add(new Text({\n            name: 'pageText',\n            style: {\n                textFill: pageTextStyleModel.getTextColor(),\n                font: pageTextStyleModel.getFont(),\n                textVerticalAlign: 'middle',\n                textAlign: 'center'\n            },\n            silent: true\n        }));\n\n        createPageButton('pageNext', 1);\n\n        function createPageButton(name, iconIdx) {\n            var pageDataIndexName = name + 'DataIndex';\n            var icon = createIcon(\n                legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx],\n                {\n                    // Buttons will be created in each render, so we do not need\n                    // to worry about avoiding using legendModel kept in scope.\n                    onclick: bind(\n                        me._pageGo, me, pageDataIndexName, legendModel, api\n                    )\n                },\n                {\n                    x: -pageIconSize[0] / 2,\n                    y: -pageIconSize[1] / 2,\n                    width: pageIconSize[0],\n                    height: pageIconSize[1]\n                }\n            );\n            icon.name = name;\n            controllerGroup.add(icon);\n        }\n    },\n\n    /**\n     * @override\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender) {\n        var contentGroup = this.getContentGroup();\n        var containerGroup = this._containerGroup;\n        var controllerGroup = this._controllerGroup;\n\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH$1[orientIdx];\n        var hw = WH$1[1 - orientIdx];\n        var yx = XY$1[1 - orientIdx];\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            !orientIdx ? null : maxSize.width,\n            orientIdx ? null : maxSize.height\n        );\n\n        box(\n            // Buttons in controller are layout always horizontally.\n            'horizontal',\n            controllerGroup,\n            legendModel.get('pageButtonItemGap', true)\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        var controllerRect = controllerGroup.getBoundingRect();\n        var showController = this._showController = contentRect[wh] > maxSize[wh];\n\n        var contentPos = [-contentRect.x, -contentRect.y];\n        // Remain contentPos when scroll animation perfroming.\n        // If first rendering, `contentGroup.position` is [0, 0], which\n        // does not make sense and may cause unexepcted animation if adopted.\n        if (!isFirstRender) {\n            contentPos[orientIdx] = contentGroup.position[orientIdx];\n        }\n\n        // Layout container group based on 0.\n        var containerPos = [0, 0];\n        var controllerPos = [-controllerRect.x, -controllerRect.y];\n        var pageButtonGap = retrieve2(\n            legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)\n        );\n\n        // Place containerGroup and controllerGroup and contentGroup.\n        if (showController) {\n            var pageButtonPosition = legendModel.get('pageButtonPosition', true);\n            // controller is on the right / bottom.\n            if (pageButtonPosition === 'end') {\n                controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh];\n            }\n            // controller is on the left / top.\n            else {\n                containerPos[orientIdx] += controllerRect[wh] + pageButtonGap;\n            }\n        }\n\n        // Always align controller to content as 'middle'.\n        controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2;\n\n        contentGroup.attr('position', contentPos);\n        containerGroup.attr('position', containerPos);\n        controllerGroup.attr('position', controllerPos);\n\n        // Calculate `mainRect` and set `clipPath`.\n        // mainRect should not be calculated by `this.group.getBoundingRect()`\n        // for sake of the overflow.\n        var mainRect = this.group.getBoundingRect();\n        var mainRect = {x: 0, y: 0};\n        // Consider content may be overflow (should be clipped).\n        mainRect[wh] = showController ? maxSize[wh] : contentRect[wh];\n        mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]);\n        // `containerRect[yx] + containerPos[1 - orientIdx]` is 0.\n        mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]);\n\n        containerGroup.__rectSize = maxSize[wh];\n        if (showController) {\n            var clipShape = {x: 0, y: 0};\n            clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0);\n            clipShape[hw] = mainRect[hw];\n            containerGroup.setClipPath(new Rect({shape: clipShape}));\n            // Consider content may be larger than container, container rect\n            // can not be obtained from `containerGroup.getBoundingRect()`.\n            containerGroup.__rectSize = clipShape[wh];\n        }\n        else {\n            // Do not remove or ignore controller. Keep them set as place holders.\n            controllerGroup.eachChild(function (child) {\n                child.attr({invisible: true, silent: true});\n            });\n        }\n\n        // Content translate animation.\n        var pageInfo = this._getPageInfo(legendModel);\n        pageInfo.pageIndex != null && updateProps(\n            contentGroup,\n            {position: pageInfo.contentPosition},\n            // When switch from \"show controller\" to \"not show controller\", view should be\n            // updated immediately without animation, otherwise causes weird efffect.\n            showController ? legendModel : false\n        );\n\n        this._updatePageInfoView(legendModel, pageInfo);\n\n        return mainRect;\n    },\n\n    _pageGo: function (to, legendModel, api) {\n        var scrollDataIndex = this._getPageInfo(legendModel)[to];\n\n        scrollDataIndex != null && api.dispatchAction({\n            type: 'legendScroll',\n            scrollDataIndex: scrollDataIndex,\n            legendId: legendModel.id\n        });\n    },\n\n    _updatePageInfoView: function (legendModel, pageInfo) {\n        var controllerGroup = this._controllerGroup;\n\n        each$1(['pagePrev', 'pageNext'], function (name) {\n            var canJump = pageInfo[name + 'DataIndex'] != null;\n            var icon = controllerGroup.childOfName(name);\n            if (icon) {\n                icon.setStyle(\n                    'fill',\n                    canJump\n                        ? legendModel.get('pageIconColor', true)\n                        : legendModel.get('pageIconInactiveColor', true)\n                );\n                icon.cursor = canJump ? 'pointer' : 'default';\n            }\n        });\n\n        var pageText = controllerGroup.childOfName('pageText');\n        var pageFormatter = legendModel.get('pageFormatter');\n        var pageIndex = pageInfo.pageIndex;\n        var current = pageIndex != null ? pageIndex + 1 : 0;\n        var total = pageInfo.pageCount;\n\n        pageText && pageFormatter && pageText.setStyle(\n            'text',\n            isString(pageFormatter)\n                ? pageFormatter.replace('{current}', current).replace('{total}', total)\n                : pageFormatter({current: current, total: total})\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Model} legendModel\n     * @return {Object} {\n     *  contentPosition: Array.<number>, null when data item not found.\n     *  pageIndex: number, null when data item not found.\n     *  pageCount: number, always be a number, can be 0.\n     *  pagePrevDataIndex: number, null when no next page.\n     *  pageNextDataIndex: number, null when no previous page.\n     * }\n     */\n    _getPageInfo: function (legendModel) {\n        var scrollDataIndex = legendModel.get('scrollDataIndex', true);\n        var contentGroup = this.getContentGroup();\n        var containerRectSize = this._containerGroup.__rectSize;\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH$1[orientIdx];\n        var xy = XY$1[orientIdx];\n        var targetItemIndex = this._findTargetItemIndex(scrollDataIndex);\n        var children = contentGroup.children();\n        var targetItem = children[targetItemIndex];\n        var itemCount = children.length;\n        var pCount = !itemCount ? 0 : 1;\n\n        var result = {\n            contentPosition: contentGroup.position.slice(),\n            pageCount: pCount,\n            pageIndex: pCount - 1,\n            pagePrevDataIndex: null,\n            pageNextDataIndex: null\n        };\n\n        if (!targetItem) {\n            return result;\n        }\n\n        var targetItemInfo = getItemInfo(targetItem);\n        result.contentPosition[orientIdx] = -targetItemInfo.s;\n\n        // Strategy:\n        // (1) Always align based on the left/top most item.\n        // (2) It is user-friendly that the last item shown in the\n        // current window is shown at the begining of next window.\n        // Otherwise if half of the last item is cut by the window,\n        // it will have no chance to display entirely.\n        // (3) Consider that item size probably be different, we\n        // have calculate pageIndex by size rather than item index,\n        // and we can not get page index directly by division.\n        // (4) The window is to narrow to contain more than\n        // one item, we should make sure that the page can be fliped.\n\n        for (var i = targetItemIndex + 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i <= itemCount;\n            ++i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // Half of the last item is out of the window.\n                (!currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize)\n                // If the current item does not intersect with the window, the new page\n                // can be started at the current item or the last item.\n                || (currItemInfo && !intersect(currItemInfo, winStartItemInfo.s))\n            ) {\n                if (winEndItemInfo.i > winStartItemInfo.i) {\n                    winStartItemInfo = winEndItemInfo;\n                }\n                else { // e.g., when page size is smaller than item size.\n                    winStartItemInfo = currItemInfo;\n                }\n                if (winStartItemInfo) {\n                    if (result.pageNextDataIndex == null) {\n                        result.pageNextDataIndex = winStartItemInfo.i;\n                    }\n                    ++result.pageCount;\n                }\n            }\n            winEndItemInfo = currItemInfo;\n        }\n\n        for (var i = targetItemIndex - 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i >= -1;\n            --i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // If the the end item does not intersect with the window started\n                // from the current item, a page can be settled.\n                (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s))\n                // e.g., when page size is smaller than item size.\n                && winStartItemInfo.i < winEndItemInfo.i\n            ) {\n                winEndItemInfo = winStartItemInfo;\n                if (result.pagePrevDataIndex == null) {\n                    result.pagePrevDataIndex = winStartItemInfo.i;\n                }\n                ++result.pageCount;\n                ++result.pageIndex;\n            }\n            winStartItemInfo = currItemInfo;\n        }\n\n        return result;\n\n        function getItemInfo(el) {\n            if (el) {\n                var itemRect = el.getBoundingRect();\n                var start = itemRect[xy] + el.position[orientIdx];\n                return {\n                    s: start,\n                    e: start + itemRect[wh],\n                    i: el.__legendDataIndex\n                };\n            }\n        }\n\n        function intersect(itemInfo, winStart) {\n            return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize;\n        }\n    },\n\n    _findTargetItemIndex: function (targetDataIndex) {\n        var index;\n        var contentGroup = this.getContentGroup();\n        if (this._showController) {\n            contentGroup.eachChild(function (child, idx) {\n                if (child.__legendDataIndex === targetDataIndex) {\n                    index = idx;\n                }\n            });\n        }\n        else {\n            index = 0;\n        }\n        return index;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @event legendScroll\n * @type {Object}\n * @property {string} type 'legendScroll'\n * @property {string} scrollDataIndex\n */\nregisterAction(\n    'legendScroll', 'legendscroll',\n    function (payload, ecModel) {\n        var scrollDataIndex = payload.scrollDataIndex;\n\n        scrollDataIndex != null && ecModel.eachComponent(\n            {mainType: 'legend', subType: 'scroll', query: payload},\n            function (legendModel) {\n                legendModel.setScrollDataIndex(scrollDataIndex);\n            }\n        );\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Legend component entry file8\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'tooltip',\n\n    dependencies: ['axisPointer'],\n\n    defaultOption: {\n        zlevel: 0,\n\n        z: 60,\n\n        show: true,\n\n        // tooltip主体内容\n        showContent: true,\n\n        // 'trigger' only works on coordinate system.\n        // 'item' | 'axis' | 'none'\n        trigger: 'item',\n\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: 'mousemove|click',\n\n        alwaysShowContent: false,\n\n        displayMode: 'single', // 'single' | 'multipleByCoordSys'\n\n        renderMode: 'auto', // 'auto' | 'html' | 'richText'\n        // 'auto': use html by default, and use non-html if `document` is not defined\n        // 'html': use html for tooltip\n        // 'richText': use canvas, svg, and etc. for tooltip\n\n        // 位置 {Array} | {Function}\n        // position: null\n        // Consider triggered from axisPointer handle, verticalAlign should be 'middle'\n        // align: null,\n        // verticalAlign: null,\n\n        // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。\n        confine: false,\n\n        // 内容格式器：{string}（Template） ¦ {Function}\n        // formatter: null\n\n        showDelay: 0,\n\n        // 隐藏延迟，单位ms\n        hideDelay: 100,\n\n        // 动画变换时间，单位s\n        transitionDuration: 0.4,\n\n        enterable: false,\n\n        // 提示背景颜色，默认为透明度为0.7的黑色\n        backgroundColor: 'rgba(50,50,50,0.7)',\n\n        // 提示边框颜色\n        borderColor: '#333',\n\n        // 提示边框圆角，单位px，默认为4\n        borderRadius: 4,\n\n        // 提示边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 提示内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // Extra css text\n        extraCssText: '',\n\n        // 坐标轴指示器，坐标轴触发有效\n        axisPointer: {\n            // 默认为直线\n            // 可选为：'line' | 'shadow' | 'cross'\n            type: 'line',\n\n            // type 为 line 的时候有效，指定 tooltip line 所在的轴，可选\n            // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'\n            // 默认 'auto'，会选择类型为 category 的轴，对于双数值轴，笛卡尔坐标系会默认选择 x 轴\n            // 极坐标系会默认选择 angle 轴\n            axis: 'auto',\n\n            animation: 'auto',\n            animationDurationUpdate: 200,\n            animationEasingUpdate: 'exponentialOut',\n\n            crossStyle: {\n                color: '#999',\n                width: 1,\n                type: 'dashed',\n\n                // TODO formatter\n                textStyle: {}\n            }\n\n            // lineStyle and shadowStyle should not be specified here,\n            // otherwise it will always override those styles on option.axisPointer.\n        },\n        textStyle: {\n            color: '#fff',\n            fontSize: 14\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$18 = each$1;\nvar toCamelCase$1 = toCamelCase;\n\nvar vendors = ['', '-webkit-', '-moz-', '-o-'];\n\nvar gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';\n\n/**\n * @param {number} duration\n * @return {string}\n * @inner\n */\nfunction assembleTransition(duration) {\n    var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';\n    var transitionText = 'left ' + duration + 's ' + transitionCurve + ','\n                        + 'top ' + duration + 's ' + transitionCurve;\n    return map(vendors, function (vendorPrefix) {\n        return vendorPrefix + 'transition:' + transitionText;\n    }).join(';');\n}\n\n/**\n * @param {Object} textStyle\n * @return {string}\n * @inner\n */\nfunction assembleFont(textStyleModel) {\n    var cssText = [];\n\n    var fontSize = textStyleModel.get('fontSize');\n    var color = textStyleModel.getTextColor();\n\n    color && cssText.push('color:' + color);\n\n    cssText.push('font:' + textStyleModel.getFont());\n\n    fontSize\n        && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');\n\n    each$18(['decoration', 'align'], function (name) {\n        var val = textStyleModel.get(name);\n        val && cssText.push('text-' + name + ':' + val);\n    });\n\n    return cssText.join(';');\n}\n\n/**\n * @param {Object} tooltipModel\n * @return {string}\n * @inner\n */\nfunction assembleCssText(tooltipModel) {\n\n    var cssText = [];\n\n    var transitionDuration = tooltipModel.get('transitionDuration');\n    var backgroundColor = tooltipModel.get('backgroundColor');\n    var textStyleModel = tooltipModel.getModel('textStyle');\n    var padding = tooltipModel.get('padding');\n\n    // Animation transition. Do not animate when transitionDuration is 0.\n    transitionDuration\n        && cssText.push(assembleTransition(transitionDuration));\n\n    if (backgroundColor) {\n        if (env$1.canvasSupported) {\n            cssText.push('background-Color:' + backgroundColor);\n        }\n        else {\n            // for ie\n            cssText.push(\n                'background-Color:#' + toHex(backgroundColor)\n            );\n            cssText.push('filter:alpha(opacity=70)');\n        }\n    }\n\n    // Border style\n    each$18(['width', 'color', 'radius'], function (name) {\n        var borderName = 'border-' + name;\n        var camelCase = toCamelCase$1(borderName);\n        var val = tooltipModel.get(camelCase);\n        val != null\n            && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));\n    });\n\n    // Text style\n    cssText.push(assembleFont(textStyleModel));\n\n    // Padding\n    if (padding != null) {\n        cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px');\n    }\n\n    return cssText.join(';') + ';';\n}\n\n/**\n * @alias module:echarts/component/tooltip/TooltipContent\n * @constructor\n */\nfunction TooltipContent(container, api) {\n    if (env$1.wxa) {\n        return null;\n    }\n\n    var el = document.createElement('div');\n    var zr = this._zr = api.getZr();\n\n    this.el = el;\n\n    this._x = api.getWidth() / 2;\n    this._y = api.getHeight() / 2;\n\n    container.appendChild(el);\n\n    this._container = container;\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n\n    var self = this;\n    el.onmouseenter = function () {\n        // clear the timeout in hideLater and keep showing tooltip\n        if (self._enterable) {\n            clearTimeout(self._hideTimeout);\n            self._show = true;\n        }\n        self._inContent = true;\n    };\n    el.onmousemove = function (e) {\n        e = e || window.event;\n        if (!self._enterable) {\n            // Try trigger zrender event to avoid mouse\n            // in and out shape too frequently\n            var handler = zr.handler;\n            normalizeEvent(container, e, true);\n            handler.dispatch('mousemove', e);\n        }\n    };\n    el.onmouseleave = function () {\n        if (self._enterable) {\n            if (self._show) {\n                self.hideLater(self._hideDelay);\n            }\n        }\n        self._inContent = false;\n    };\n}\n\nTooltipContent.prototype = {\n\n    constructor: TooltipContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // FIXME\n        // Move this logic to ec main?\n        var container = this._container;\n        var stl = container.currentStyle\n            || document.defaultView.getComputedStyle(container);\n        var domStyle = container.style;\n        if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {\n            domStyle.position = 'relative';\n        }\n        // Hide the tooltip\n        // PENDING\n        // this.hide();\n    },\n\n    show: function (tooltipModel) {\n        clearTimeout(this._hideTimeout);\n        var el = this.el;\n\n        el.style.cssText = gCssText + assembleCssText(tooltipModel)\n            // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore\n            + ';left:' + this._x + 'px;top:' + this._y + 'px;'\n            + (tooltipModel.get('extraCssText') || '');\n\n        el.style.display = el.innerHTML ? 'block' : 'none';\n\n        // If mouse occsionally move over the tooltip, a mouseout event will be\n        // triggered by canvas, and cuase some unexpectable result like dragging\n        // stop, \"unfocusAdjacency\". Here `pointer-events: none` is used to solve\n        // it. Although it is not suppored by IE8~IE10, fortunately it is a rare\n        // scenario.\n        el.style.pointerEvents = this._enterable ? 'auto' : 'none';\n\n        this._show = true;\n    },\n\n    setContent: function (content) {\n        this.el.innerHTML = content == null ? '' : content;\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var el = this.el;\n        return [el.clientWidth, el.clientHeight];\n    },\n\n    moveTo: function (x, y) {\n        // xy should be based on canvas root. But tooltipContent is\n        // the sibling of canvas root. So padding of ec container\n        // should be considered here.\n        var zr = this._zr;\n        var viewportRootOffset;\n        if (zr && zr.painter && (viewportRootOffset = zr.painter.getViewportRootOffset())) {\n            x += viewportRootOffset.offsetLeft;\n            y += viewportRootOffset.offsetTop;\n        }\n\n        var style = this.el.style;\n        style.left = x + 'px';\n        style.top = y + 'px';\n\n        this._x = x;\n        this._y = y;\n    },\n\n    hide: function () {\n        this.el.style.display = 'none';\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        var width = this.el.clientWidth;\n        var height = this.el.clientHeight;\n\n        // Consider browser compatibility.\n        // IE8 does not support getComputedStyle.\n        if (document.defaultView && document.defaultView.getComputedStyle) {\n            var stl = document.defaultView.getComputedStyle(this.el);\n            if (stl) {\n                width += parseInt(stl.paddingLeft, 10) + parseInt(stl.paddingRight, 10)\n                    + parseInt(stl.borderLeftWidth, 10) + parseInt(stl.borderRightWidth, 10);\n                height += parseInt(stl.paddingTop, 10) + parseInt(stl.paddingBottom, 10)\n                    + parseInt(stl.borderTopWidth, 10) + parseInt(stl.borderBottomWidth, 10);\n            }\n        }\n\n        return {width: width, height: height};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Group from 'zrender/src/container/Group';\n/**\n * @alias module:echarts/component/tooltip/TooltipRichContent\n * @constructor\n */\nfunction TooltipRichContent(api) {\n\n    this._zr = api.getZr();\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n}\n\nTooltipRichContent.prototype = {\n\n    constructor: TooltipRichContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // noop\n    },\n\n    show: function (tooltipModel) {\n        if (this._hideTimeout) {\n            clearTimeout(this._hideTimeout);\n        }\n\n        this.el.attr('show', true);\n        this._show = true;\n    },\n\n    /**\n     * Set tooltip content\n     *\n     * @param {string} content rich text string of content\n     * @param {Object} markerRich rich text style\n     * @param {Object} tooltipModel tooltip model\n     */\n    setContent: function (content, markerRich, tooltipModel) {\n        if (this.el) {\n            this._zr.remove(this.el);\n        }\n\n        var markers = {};\n        var text = content;\n        var prefix = '{marker';\n        var suffix = '|}';\n        var startId = text.indexOf(prefix);\n        while (startId >= 0) {\n            var endId = text.indexOf(suffix);\n            var name = text.substr(startId + prefix.length, endId - startId - prefix.length);\n            if (name.indexOf('sub') > -1) {\n                markers['marker' + name] = {\n                    textWidth: 4,\n                    textHeight: 4,\n                    textBorderRadius: 2,\n                    textBackgroundColor: markerRich[name],\n                    // TODO: textOffset is not implemented for rich text\n                    textOffset: [3, 0]\n                };\n            }\n            else {\n                markers['marker' + name] = {\n                    textWidth: 10,\n                    textHeight: 10,\n                    textBorderRadius: 5,\n                    textBackgroundColor: markerRich[name]\n                };\n            }\n\n            text = text.substr(endId + 1);\n            startId = text.indexOf('{marker');\n        }\n\n        this.el = new Text({\n            style: {\n                rich: markers,\n                text: content,\n                textLineHeight: 20,\n                textBackgroundColor: tooltipModel.get('backgroundColor'),\n                textBorderRadius: tooltipModel.get('borderRadius'),\n                textFill: tooltipModel.get('textStyle.color'),\n                textPadding: tooltipModel.get('padding')\n            },\n            z: tooltipModel.get('z')\n        });\n        this._zr.add(this.el);\n\n        var self = this;\n        this.el.on('mouseover', function () {\n            // clear the timeout in hideLater and keep showing tooltip\n            if (self._enterable) {\n                clearTimeout(self._hideTimeout);\n                self._show = true;\n            }\n            self._inContent = true;\n        });\n        this.el.on('mouseout', function () {\n            if (self._enterable) {\n                if (self._show) {\n                    self.hideLater(self._hideDelay);\n                }\n            }\n            self._inContent = false;\n        });\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var bounding = this.el.getBoundingRect();\n        return [bounding.width, bounding.height];\n    },\n\n    moveTo: function (x, y) {\n        if (this.el) {\n            this.el.attr('position', [x, y]);\n        }\n    },\n\n    hide: function () {\n        this.el.hide();\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        return this.getSize();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$3 = bind;\nvar each$17 = each$1;\nvar parsePercent$2 = parsePercent$1;\n\nvar proxyRect = new Rect({\n    shape: {x: -1, y: -1, width: 2, height: 2}\n});\n\nextendComponentView({\n\n    type: 'tooltip',\n\n    init: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        var tooltipModel = ecModel.getComponent('tooltip');\n        var renderMode = tooltipModel.get('renderMode');\n        this._renderMode = getTooltipRenderMode(renderMode);\n\n        var tooltipContent;\n        if (this._renderMode === 'html') {\n            tooltipContent = new TooltipContent(api.getDom(), api);\n            this._newLine = '<br/>';\n        }\n        else {\n            tooltipContent = new TooltipRichContent(api);\n            this._newLine = '\\n';\n        }\n\n        this._tooltipContent = tooltipContent;\n    },\n\n    render: function (tooltipModel, ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        // Reset\n        this.group.removeAll();\n\n        /**\n         * @private\n         * @type {module:echarts/component/tooltip/TooltipModel}\n         */\n        this._tooltipModel = tooltipModel;\n\n        /**\n         * @private\n         * @type {module:echarts/model/Global}\n         */\n        this._ecModel = ecModel;\n\n        /**\n         * @private\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this._api = api;\n\n        /**\n         * Should be cleaned when render.\n         * @private\n         * @type {Array.<Array.<Object>>}\n         */\n        this._lastDataByCoordSys = null;\n\n        /**\n         * @private\n         * @type {boolean}\n         */\n        this._alwaysShowContent = tooltipModel.get('alwaysShowContent');\n\n        var tooltipContent = this._tooltipContent;\n        tooltipContent.update();\n        tooltipContent.setEnterable(tooltipModel.get('enterable'));\n\n        this._initGlobalListener();\n\n        this._keepShow();\n    },\n\n    _initGlobalListener: function () {\n        var tooltipModel = this._tooltipModel;\n        var triggerOn = tooltipModel.get('triggerOn');\n\n        register(\n            'itemTooltip',\n            this._api,\n            bind$3(function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none') {\n                    if (triggerOn.indexOf(currTrigger) >= 0) {\n                        this._tryShow(e, dispatchAction);\n                    }\n                    else if (currTrigger === 'leave') {\n                        this._hide(dispatchAction);\n                    }\n                }\n            }, this)\n        );\n    },\n\n    _keepShow: function () {\n        var tooltipModel = this._tooltipModel;\n        var ecModel = this._ecModel;\n        var api = this._api;\n\n        // Try to keep the tooltip show when refreshing\n        if (this._lastX != null\n            && this._lastY != null\n            // When user is willing to control tooltip totally using API,\n            // self.manuallyShowTip({x, y}) might cause tooltip hide,\n            // which is not expected.\n            && tooltipModel.get('triggerOn') !== 'none'\n        ) {\n            var self = this;\n            clearTimeout(this._refreshUpdateTimeout);\n            this._refreshUpdateTimeout = setTimeout(function () {\n                // Show tip next tick after other charts are rendered\n                // In case highlight action has wrong result\n                // FIXME\n                self.manuallyShowTip(tooltipModel, ecModel, api, {\n                    x: self._lastX,\n                    y: self._lastY\n                });\n            });\n        }\n    },\n\n    /**\n     * Show tip manually by\n     * dispatchAction({\n     *     type: 'showTip',\n     *     x: 10,\n     *     y: 10\n     * });\n     * Or\n     * dispatchAction({\n     *      type: 'showTip',\n     *      seriesIndex: 0,\n     *      dataIndex or dataIndexInside or name\n     * });\n     *\n     *  TODO Batch\n     */\n    manuallyShowTip: function (tooltipModel, ecModel, api, payload) {\n        if (payload.from === this.uid || env$1.node) {\n            return;\n        }\n\n        var dispatchAction = makeDispatchAction$1(payload, api);\n\n        // Reset ticket\n        this._ticket = '';\n\n        // When triggered from axisPointer.\n        var dataByCoordSys = payload.dataByCoordSys;\n\n        if (payload.tooltip && payload.x != null && payload.y != null) {\n            var el = proxyRect;\n            el.position = [payload.x, payload.y];\n            el.update();\n            el.tooltip = payload.tooltip;\n            // Manually show tooltip while view is not using zrender elements.\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                target: el\n            }, dispatchAction);\n        }\n        else if (dataByCoordSys) {\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                event: {},\n                dataByCoordSys: payload.dataByCoordSys,\n                tooltipOption: payload.tooltipOption\n            }, dispatchAction);\n        }\n        else if (payload.seriesIndex != null) {\n\n            if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) {\n                return;\n            }\n\n            var pointInfo = findPointFromSeries(payload, ecModel);\n            var cx = pointInfo.point[0];\n            var cy = pointInfo.point[1];\n            if (cx != null && cy != null) {\n                this._tryShow({\n                    offsetX: cx,\n                    offsetY: cy,\n                    position: payload.position,\n                    target: pointInfo.el,\n                    event: {}\n                }, dispatchAction);\n            }\n        }\n        else if (payload.x != null && payload.y != null) {\n            // FIXME\n            // should wrap dispatchAction like `axisPointer/globalListener` ?\n            api.dispatchAction({\n                type: 'updateAxisPointer',\n                x: payload.x,\n                y: payload.y\n            });\n\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                target: api.getZr().findHover(payload.x, payload.y).target,\n                event: {}\n            }, dispatchAction);\n        }\n    },\n\n    manuallyHideTip: function (tooltipModel, ecModel, api, payload) {\n        var tooltipContent = this._tooltipContent;\n\n        if (!this._alwaysShowContent && this._tooltipModel) {\n            tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));\n        }\n\n        this._lastX = this._lastY = null;\n\n        if (payload.from !== this.uid) {\n            this._hide(makeDispatchAction$1(payload, api));\n        }\n    },\n\n    // Be compatible with previous design, that is, when tooltip.type is 'axis' and\n    // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer\n    // and tooltip.\n    _manuallyAxisShowTip: function (tooltipModel, ecModel, api, payload) {\n        var seriesIndex = payload.seriesIndex;\n        var dataIndex = payload.dataIndex;\n        var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n        if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) {\n            return;\n        }\n\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n        if (!seriesModel) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            seriesModel,\n            (seriesModel.coordinateSystem || {}).model,\n            tooltipModel\n        ]);\n\n        if (tooltipModel.get('trigger') !== 'axis') {\n            return;\n        }\n\n        api.dispatchAction({\n            type: 'updateAxisPointer',\n            seriesIndex: seriesIndex,\n            dataIndex: dataIndex,\n            position: payload.position\n        });\n\n        return true;\n    },\n\n    _tryShow: function (e, dispatchAction) {\n        var el = e.target;\n        var tooltipModel = this._tooltipModel;\n\n        if (!tooltipModel) {\n            return;\n        }\n\n        // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed\n        this._lastX = e.offsetX;\n        this._lastY = e.offsetY;\n\n        var dataByCoordSys = e.dataByCoordSys;\n        if (dataByCoordSys && dataByCoordSys.length) {\n            this._showAxisTooltip(dataByCoordSys, e);\n        }\n        // Always show item tooltip if mouse is on the element with dataIndex\n        else if (el && el.dataIndex != null) {\n            this._lastDataByCoordSys = null;\n            this._showSeriesItemTooltip(e, el, dispatchAction);\n        }\n        // Tooltip provided directly. Like legend.\n        else if (el && el.tooltip) {\n            this._lastDataByCoordSys = null;\n            this._showComponentItemTooltip(e, el, dispatchAction);\n        }\n        else {\n            this._lastDataByCoordSys = null;\n            this._hide(dispatchAction);\n        }\n    },\n\n    _showOrMove: function (tooltipModel, cb) {\n        // showDelay is used in this case: tooltip.enterable is set\n        // as true. User intent to move mouse into tooltip and click\n        // something. `showDelay` makes it easyer to enter the content\n        // but tooltip do not move immediately.\n        var delay = tooltipModel.get('showDelay');\n        cb = bind(cb, this);\n        clearTimeout(this._showTimout);\n        delay > 0\n            ? (this._showTimout = setTimeout(cb, delay))\n            : cb();\n    },\n\n    _showAxisTooltip: function (dataByCoordSys, e) {\n        var ecModel = this._ecModel;\n        var globalTooltipModel = this._tooltipModel;\n        var point = [e.offsetX, e.offsetY];\n        var singleDefaultHTML = [];\n        var singleParamsList = [];\n        var singleTooltipModel = buildTooltipModel([\n            e.tooltipOption,\n            globalTooltipModel\n        ]);\n\n        var renderMode = this._renderMode;\n        var newLine = this._newLine;\n\n        var markers = {};\n\n        each$17(dataByCoordSys, function (itemCoordSys) {\n            // var coordParamList = [];\n            // var coordDefaultHTML = [];\n            // var coordTooltipModel = buildTooltipModel([\n            //     e.tooltipOption,\n            //     itemCoordSys.tooltipOption,\n            //     ecModel.getComponent(itemCoordSys.coordSysMainType, itemCoordSys.coordSysIndex),\n            //     globalTooltipModel\n            // ]);\n            // var displayMode = coordTooltipModel.get('displayMode');\n            // var paramsList = displayMode === 'single' ? singleParamsList : [];\n\n            each$17(itemCoordSys.dataByAxis, function (item) {\n                var axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex);\n                var axisValue = item.value;\n                var seriesDefaultHTML = [];\n\n                if (!axisModel || axisValue == null) {\n                    return;\n                }\n\n                var valueLabel = getValueLabel(\n                    axisValue, axisModel.axis, ecModel,\n                    item.seriesDataIndices,\n                    item.valueLabelOpt\n                );\n\n                each$1(item.seriesDataIndices, function (idxItem) {\n                    var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n                    var dataIndex = idxItem.dataIndexInside;\n                    var dataParams = series && series.getDataParams(dataIndex);\n                    dataParams.axisDim = item.axisDim;\n                    dataParams.axisIndex = item.axisIndex;\n                    dataParams.axisType = item.axisType;\n                    dataParams.axisId = item.axisId;\n                    dataParams.axisValue = getAxisRawValue(axisModel.axis, axisValue);\n                    dataParams.axisValueLabel = valueLabel;\n\n                    if (dataParams) {\n                        singleParamsList.push(dataParams);\n                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode);\n\n                        var html;\n                        if (isObject$1(seriesTooltip)) {\n                            html = seriesTooltip.html;\n                            var newMarkers = seriesTooltip.markers;\n                            merge(markers, newMarkers);\n                        }\n                        else {\n                            html = seriesTooltip;\n                        }\n                        seriesDefaultHTML.push(html);\n                    }\n                });\n\n                // Default tooltip content\n                // FIXME\n                // (1) shold be the first data which has name?\n                // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.\n                var firstLine = valueLabel;\n                if (renderMode !== 'html') {\n                    singleDefaultHTML.push(seriesDefaultHTML.join(newLine));\n                }\n                else {\n                    singleDefaultHTML.push(\n                        (firstLine ? encodeHTML(firstLine) + newLine : '')\n                        + seriesDefaultHTML.join(newLine)\n                    );\n                }\n            });\n        }, this);\n\n        // In most case, the second axis is shown upper than the first one.\n        singleDefaultHTML.reverse();\n        singleDefaultHTML = singleDefaultHTML.join(this._newLine + this._newLine);\n\n        var positionExpr = e.position;\n        this._showOrMove(singleTooltipModel, function () {\n            if (this._updateContentNotChangedOnAxis(dataByCoordSys)) {\n                this._updatePosition(\n                    singleTooltipModel,\n                    positionExpr,\n                    point[0], point[1],\n                    this._tooltipContent,\n                    singleParamsList\n                );\n            }\n            else {\n                this._showTooltipContent(\n                    singleTooltipModel, singleDefaultHTML, singleParamsList, Math.random(),\n                    point[0], point[1], positionExpr, undefined, markers\n                );\n            }\n        });\n\n        // Do not trigger events here, because this branch only be entered\n        // from dispatchAction.\n    },\n\n    _showSeriesItemTooltip: function (e, el, dispatchAction) {\n        var ecModel = this._ecModel;\n        // Use dataModel in element if possible\n        // Used when mouseover on a element like markPoint or edge\n        // In which case, the data is not main data in series.\n        var seriesIndex = el.seriesIndex;\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n        // For example, graph link.\n        var dataModel = el.dataModel || seriesModel;\n        var dataIndex = el.dataIndex;\n        var dataType = el.dataType;\n        var data = dataModel.getData();\n\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            dataModel,\n            seriesModel && (seriesModel.coordinateSystem || {}).model,\n            this._tooltipModel\n        ]);\n\n        var tooltipTrigger = tooltipModel.get('trigger');\n        if (tooltipTrigger != null && tooltipTrigger !== 'item') {\n            return;\n        }\n\n        var params = dataModel.getDataParams(dataIndex, dataType);\n        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode);\n        var defaultHtml;\n        var markers;\n        if (isObject$1(seriesTooltip)) {\n            defaultHtml = seriesTooltip.html;\n            markers = seriesTooltip.markers;\n        }\n        else {\n            defaultHtml = seriesTooltip;\n            markers = null;\n        }\n\n        var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;\n\n        this._showOrMove(tooltipModel, function () {\n            this._showTooltipContent(\n                tooltipModel, defaultHtml, params, asyncTicket,\n                e.offsetX, e.offsetY, e.position, e.target, markers\n            );\n        });\n\n        // FIXME\n        // duplicated showtip if manuallyShowTip is called from dispatchAction.\n        dispatchAction({\n            type: 'showTip',\n            dataIndexInside: dataIndex,\n            dataIndex: data.getRawIndex(dataIndex),\n            seriesIndex: seriesIndex,\n            from: this.uid\n        });\n    },\n\n    _showComponentItemTooltip: function (e, el, dispatchAction) {\n        var tooltipOpt = el.tooltip;\n        if (typeof tooltipOpt === 'string') {\n            var content = tooltipOpt;\n            tooltipOpt = {\n                content: content,\n                // Fixed formatter\n                formatter: content\n            };\n        }\n        var subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel);\n        var defaultHtml = subTooltipModel.get('content');\n        var asyncTicket = Math.random();\n\n        // Do not check whether `trigger` is 'none' here, because `trigger`\n        // only works on cooridinate system. In fact, we have not found case\n        // that requires setting `trigger` nothing on component yet.\n\n        this._showOrMove(subTooltipModel, function () {\n            this._showTooltipContent(\n                subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {},\n                asyncTicket, e.offsetX, e.offsetY, e.position, el\n            );\n        });\n\n        // If not dispatch showTip, tip may be hide triggered by axis.\n        dispatchAction({\n            type: 'showTip',\n            from: this.uid\n        });\n    },\n\n    _showTooltipContent: function (\n        tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markers\n    ) {\n        // Reset ticket\n        this._ticket = '';\n\n        if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) {\n            return;\n        }\n\n        var tooltipContent = this._tooltipContent;\n\n        var formatter = tooltipModel.get('formatter');\n        positionExpr = positionExpr || tooltipModel.get('position');\n        var html = defaultHtml;\n\n        if (formatter && typeof formatter === 'string') {\n            html = formatTpl(formatter, params, true);\n        }\n        else if (typeof formatter === 'function') {\n            var callback = bind$3(function (cbTicket, html) {\n                if (cbTicket === this._ticket) {\n                    tooltipContent.setContent(html, markers, tooltipModel);\n                    this._updatePosition(\n                        tooltipModel, positionExpr, x, y, tooltipContent, params, el\n                    );\n                }\n            }, this);\n            this._ticket = asyncTicket;\n            html = formatter(params, asyncTicket, callback);\n        }\n\n        tooltipContent.setContent(html, markers, tooltipModel);\n        tooltipContent.show(tooltipModel);\n\n        this._updatePosition(\n            tooltipModel, positionExpr, x, y, tooltipContent, params, el\n        );\n    },\n\n    /**\n     * @param  {string|Function|Array.<number>|Object} positionExpr\n     * @param  {number} x Mouse x\n     * @param  {number} y Mouse y\n     * @param  {boolean} confine Whether confine tooltip content in view rect.\n     * @param  {Object|<Array.<Object>} params\n     * @param  {module:zrender/Element} el target element\n     * @param  {module:echarts/ExtensionAPI} api\n     * @return {Array.<number>}\n     */\n    _updatePosition: function (tooltipModel, positionExpr, x, y, content, params, el) {\n        var viewWidth = this._api.getWidth();\n        var viewHeight = this._api.getHeight();\n        positionExpr = positionExpr || tooltipModel.get('position');\n\n        var contentSize = content.getSize();\n        var align = tooltipModel.get('align');\n        var vAlign = tooltipModel.get('verticalAlign');\n        var rect = el && el.getBoundingRect().clone();\n        el && rect.applyTransform(el.transform);\n\n        if (typeof positionExpr === 'function') {\n            // Callback of position can be an array or a string specify the position\n            positionExpr = positionExpr([x, y], params, content.el, rect, {\n                viewSize: [viewWidth, viewHeight],\n                contentSize: contentSize.slice()\n            });\n        }\n\n        if (isArray(positionExpr)) {\n            x = parsePercent$2(positionExpr[0], viewWidth);\n            y = parsePercent$2(positionExpr[1], viewHeight);\n        }\n        else if (isObject$1(positionExpr)) {\n            positionExpr.width = contentSize[0];\n            positionExpr.height = contentSize[1];\n            var layoutRect = getLayoutRect(\n                positionExpr, {width: viewWidth, height: viewHeight}\n            );\n            x = layoutRect.x;\n            y = layoutRect.y;\n            align = null;\n            // When positionExpr is left/top/right/bottom,\n            // align and verticalAlign will not work.\n            vAlign = null;\n        }\n        // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element\n        else if (typeof positionExpr === 'string' && el) {\n            var pos = calcTooltipPosition(\n                positionExpr, rect, contentSize\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n        else {\n            var pos = refixTooltipPosition(\n                x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);\n        vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);\n\n        if (tooltipModel.get('confine')) {\n            var pos = confineTooltipPosition(\n                x, y, content, viewWidth, viewHeight\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        content.moveTo(x, y);\n    },\n\n    // FIXME\n    // Should we remove this but leave this to user?\n    _updateContentNotChangedOnAxis: function (dataByCoordSys) {\n        var lastCoordSys = this._lastDataByCoordSys;\n        var contentNotChanged = !!lastCoordSys\n            && lastCoordSys.length === dataByCoordSys.length;\n\n        contentNotChanged && each$17(lastCoordSys, function (lastItemCoordSys, indexCoordSys) {\n            var lastDataByAxis = lastItemCoordSys.dataByAxis || {};\n            var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {};\n            var thisDataByAxis = thisItemCoordSys.dataByAxis || [];\n            contentNotChanged &= lastDataByAxis.length === thisDataByAxis.length;\n\n            contentNotChanged && each$17(lastDataByAxis, function (lastItem, indexAxis) {\n                var thisItem = thisDataByAxis[indexAxis] || {};\n                var lastIndices = lastItem.seriesDataIndices || [];\n                var newIndices = thisItem.seriesDataIndices || [];\n\n                contentNotChanged\n                    &= lastItem.value === thisItem.value\n                    && lastItem.axisType === thisItem.axisType\n                    && lastItem.axisId === thisItem.axisId\n                    && lastIndices.length === newIndices.length;\n\n                contentNotChanged && each$17(lastIndices, function (lastIdxItem, j) {\n                    var newIdxItem = newIndices[j];\n                    contentNotChanged\n                        &= lastIdxItem.seriesIndex === newIdxItem.seriesIndex\n                        && lastIdxItem.dataIndex === newIdxItem.dataIndex;\n                });\n            });\n        });\n\n        this._lastDataByCoordSys = dataByCoordSys;\n\n        return !!contentNotChanged;\n    },\n\n    _hide: function (dispatchAction) {\n        // Do not directly hideLater here, because this behavior may be prevented\n        // in dispatchAction when showTip is dispatched.\n\n        // FIXME\n        // duplicated hideTip if manuallyHideTip is called from dispatchAction.\n        this._lastDataByCoordSys = null;\n        dispatchAction({\n            type: 'hideTip',\n            from: this.uid\n        });\n    },\n\n    dispose: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n        this._tooltipContent.hide();\n        unregister('itemTooltip', api);\n    }\n});\n\n\n/**\n * @param {Array.<Object|module:echarts/model/Model>} modelCascade\n * From top to bottom. (the last one should be globalTooltipModel);\n */\nfunction buildTooltipModel(modelCascade) {\n    var resultModel = modelCascade.pop();\n    while (modelCascade.length) {\n        var tooltipOpt = modelCascade.pop();\n        if (tooltipOpt) {\n            if (Model.isInstance(tooltipOpt)) {\n                tooltipOpt = tooltipOpt.get('tooltip', true);\n            }\n            // In each data item tooltip can be simply write:\n            // {\n            //  value: 10,\n            //  tooltip: 'Something you need to know'\n            // }\n            if (typeof tooltipOpt === 'string') {\n                tooltipOpt = {formatter: tooltipOpt};\n            }\n            resultModel = new Model(tooltipOpt, resultModel, resultModel.ecModel);\n        }\n    }\n    return resultModel;\n}\n\nfunction makeDispatchAction$1(payload, api) {\n    return payload.dispatchAction || bind(api.dispatchAction, api);\n}\n\nfunction refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    if (gapH != null) {\n        if (x + width + gapH > viewWidth) {\n            x -= width + gapH;\n        }\n        else {\n            x += gapH;\n        }\n    }\n    if (gapV != null) {\n        if (y + height + gapV > viewHeight) {\n            y -= height + gapV;\n        }\n        else {\n            y += gapV;\n        }\n    }\n    return [x, y];\n}\n\nfunction confineTooltipPosition(x, y, content, viewWidth, viewHeight) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    x = Math.min(x + width, viewWidth) - width;\n    y = Math.min(y + height, viewHeight) - height;\n    x = Math.max(x, 0);\n    y = Math.max(y, 0);\n\n    return [x, y];\n}\n\nfunction calcTooltipPosition(position, rect, contentSize) {\n    var domWidth = contentSize[0];\n    var domHeight = contentSize[1];\n    var gap = 5;\n    var x = 0;\n    var y = 0;\n    var rectWidth = rect.width;\n    var rectHeight = rect.height;\n    switch (position) {\n        case 'inside':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'top':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y - domHeight - gap;\n            break;\n        case 'bottom':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight + gap;\n            break;\n        case 'left':\n            x = rect.x - domWidth - gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'right':\n            x = rect.x + rectWidth + gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n    }\n    return [x, y];\n}\n\nfunction isCenterAlign(align) {\n    return align === 'center' || align === 'middle';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Better way to pack data in graphic element\n\n/**\n * @action\n * @property {string} type\n * @property {number} seriesIndex\n * @property {number} dataIndex\n * @property {number} [x]\n * @property {number} [y]\n */\nregisterAction(\n    {\n        type: 'showTip',\n        event: 'showTip',\n        update: 'tooltip:manuallyShowTip'\n    },\n    // noop\n    function () {}\n);\n\nregisterAction(\n    {\n        type: 'hideTip',\n        event: 'hideTip',\n        update: 'tooltip:manuallyHideTip'\n    },\n    // noop\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getSeriesStackId$1(seriesModel) {\n    return seriesModel.get('stack')\n        || '__ec_stack_' + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey$1(axis) {\n    return axis.dim;\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction barLayoutPolar(seriesType, ecModel, api) {\n\n    // FIXME\n    // Revert becuase it brings bar progressive bug.\n    // The complete fix will be added in the next version.\n    var width = api.getWidth();\n    var height = api.getHeight();\n\n    var lastStackCoords = {};\n\n    var barWidthAndOffset = calRadialBar(\n        filter(\n            ecModel.getSeriesByType(seriesType),\n            function (seriesModel) {\n                return !ecModel.isSeriesFiltered(seriesModel)\n                    && seriesModel.coordinateSystem\n                    && seriesModel.coordinateSystem.type === 'polar';\n            }\n        )\n    );\n\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for polar only\n        if (seriesModel.coordinateSystem.type !== 'polar') {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var polar = seriesModel.coordinateSystem;\n        var baseAxis = polar.getBaseAxis();\n\n        var stackId = getSeriesStackId$1(seriesModel);\n        var columnLayoutInfo\n            = barWidthAndOffset[getAxisKey$1(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = polar.getOtherAxis(baseAxis);\n\n        var cx = seriesModel.coordinateSystem.cx;\n        var cy = seriesModel.coordinateSystem.cy;\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n        var barMinAngle = seriesModel.get('barMinAngle') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n\n        var valueAxisStart = valueAxis.getExtent()[0];\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            // Only ordinal axis can be stacked.\n            if (stacked) {\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var r0;\n            var r;\n            var startAngle;\n            var endAngle;\n\n            // radial sector\n            if (valueAxis.dim === 'radius') {\n                var radiusSpan = valueAxis.dataToRadius(value) - valueAxisStart;\n                var angle = baseAxis.dataToAngle(baseValue);\n\n                if (Math.abs(radiusSpan) < barMinHeight) {\n                    radiusSpan = (radiusSpan < 0 ? -1 : 1) * barMinHeight;\n                }\n\n                r0 = baseCoord;\n                r = baseCoord + radiusSpan;\n                startAngle = angle - columnOffset;\n                endAngle = startAngle - columnWidth;\n\n                stacked && (lastStackCoords[stackId][baseValue][sign] = r);\n            }\n            // tangential sector\n            else {\n                // angleAxis must be clamped.\n                var angleSpan = valueAxis.dataToAngle(value, true) - valueAxisStart;\n                var radius = baseAxis.dataToRadius(baseValue);\n\n                if (Math.abs(angleSpan) < barMinAngle) {\n                    angleSpan = (angleSpan < 0 ? -1 : 1) * barMinAngle;\n                }\n\n                r0 = radius + columnOffset;\n                r = r0 + columnWidth;\n                startAngle = baseCoord;\n                endAngle = baseCoord + angleSpan;\n\n                // if the previous stack is at the end of the ring,\n                // add a round to differentiate it from origin\n                // var extent = angleAxis.getExtent();\n                // var stackCoord = angle;\n                // if (stackCoord === extent[0] && value > 0) {\n                //     stackCoord = extent[1];\n                // }\n                // else if (stackCoord === extent[1] && value < 0) {\n                //     stackCoord = extent[0];\n                // }\n                stacked && (lastStackCoords[stackId][baseValue][sign] = endAngle);\n            }\n\n            data.setItemLayout(idx, {\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: r,\n                // Consider that positive angle is anti-clockwise,\n                // while positive radian of sector is clockwise\n                startAngle: -startAngle * Math.PI / 180,\n                endAngle: -endAngle * Math.PI / 180\n            });\n\n        }\n\n    }, this);\n\n}\n\n/**\n * Calculate bar width and offset for radial bar charts\n */\nfunction calRadialBar(barSeries, api) {\n    // Columns info on each category axis. Key is polar name\n    var columnsMap = {};\n\n    each$1(barSeries, function (seriesModel, idx) {\n        var data = seriesModel.getData();\n        var polar = seriesModel.coordinateSystem;\n\n        var baseAxis = polar.getBaseAxis();\n\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var columnsOnAxis = columnsMap[getAxisKey$1(baseAxis)] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[getAxisKey$1(baseAxis)] = columnsOnAxis;\n\n        var stackId = getSeriesStackId$1(seriesModel);\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'),\n            bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'),\n            bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        if (barWidth && !stacks[stackId].width) {\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            stacks[stackId].width = barWidth;\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction RadiusAxis(scale, radiusExtent) {\n\n    Axis.call(this, 'radius', scale, radiusExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'category';\n}\n\nRadiusAxis.prototype = {\n\n    constructor: RadiusAxis,\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];\n    },\n\n    dataToRadius: Axis.prototype.dataToCoord,\n\n    radiusToData: Axis.prototype.coordToData\n};\n\ninherits(RadiusAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$12 = makeInner();\n\nfunction AngleAxis(scale, angleExtent) {\n\n    angleExtent = angleExtent || [0, 360];\n\n    Axis.call(this, 'angle', scale, angleExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'category';\n}\n\nAngleAxis.prototype = {\n\n    constructor: AngleAxis,\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];\n    },\n\n    dataToAngle: Axis.prototype.dataToCoord,\n\n    angleToData: Axis.prototype.coordToData,\n\n    /**\n     * Only be called in category axis.\n     * Angle axis uses text height to decide interval\n     *\n     * @override\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        var axis = this;\n        var labelModel = axis.getLabelModel();\n\n        var ordinalScale = axis.scale;\n        var ordinalExtent = ordinalScale.getExtent();\n        // Providing this method is for optimization:\n        // avoid generating a long array by `getTicks`\n        // in large category data case.\n        var tickCount = ordinalScale.count();\n\n        if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n            return 0;\n        }\n\n        var tickValue = ordinalExtent[0];\n        var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n        var unitH = Math.abs(unitSpan);\n\n        // Not precise, just use height as text width\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            tickValue, labelModel.getFont(), 'center', 'top'\n        );\n        var maxH = Math.max(rect.height, 7);\n\n        var dh = maxH / unitH;\n        // 0/0 is NaN, 1/0 is Infinity.\n        isNaN(dh) && (dh = Infinity);\n        var interval = Math.max(0, Math.floor(dh));\n\n        var cache = inner$12(axis.model);\n        var lastAutoInterval = cache.lastAutoInterval;\n        var lastTickCount = cache.lastTickCount;\n\n        // Use cache to keep interval stable while moving zoom window,\n        // otherwise the calculated interval might jitter when the zoom\n        // window size is close to the interval-changing size.\n        if (lastAutoInterval != null\n            && lastTickCount != null\n            && Math.abs(lastAutoInterval - interval) <= 1\n            && Math.abs(lastTickCount - tickCount) <= 1\n            // Always choose the bigger one, otherwise the critical\n            // point is not the same when zooming in or zooming out.\n            && lastAutoInterval > interval\n        ) {\n            interval = lastAutoInterval;\n        }\n        // Only update cache if cache not used, otherwise the\n        // changing of interval is too insensitive.\n        else {\n            cache.lastTickCount = tickCount;\n            cache.lastAutoInterval = interval;\n        }\n\n        return interval;\n    }\n};\n\ninherits(AngleAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/polar/Polar\n */\n\n/**\n * @alias {module:echarts/coord/polar/Polar}\n * @constructor\n * @param {string} name\n */\nvar Polar = function (name) {\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n\n    /**\n     * x of polar center\n     * @type {number}\n     */\n    this.cx = 0;\n\n    /**\n     * y of polar center\n     * @type {number}\n     */\n    this.cy = 0;\n\n    /**\n     * @type {module:echarts/coord/polar/RadiusAxis}\n     * @private\n     */\n    this._radiusAxis = new RadiusAxis();\n\n    /**\n     * @type {module:echarts/coord/polar/AngleAxis}\n     * @private\n     */\n    this._angleAxis = new AngleAxis();\n\n    this._radiusAxis.polar = this._angleAxis.polar = this;\n};\n\nPolar.prototype = {\n\n    type: 'polar',\n\n    axisPointerEnabled: true,\n\n    constructor: Polar,\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['radius', 'angle'],\n\n    /**\n     * @type {module:echarts/coord/PolarModel}\n     */\n    model: null,\n\n    /**\n     * If contain coord\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var coord = this.pointToCoord(point);\n        return this._radiusAxis.contain(coord[0])\n            && this._angleAxis.contain(coord[1]);\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this._radiusAxis.containData(data[0])\n            && this._angleAxis.containData(data[1]);\n    },\n\n    /**\n     * @param {string} dim\n     * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    getAxis: function (dim) {\n        return this['_' + dim + 'Axis'];\n    },\n\n    /**\n     * @return {Array.<module:echarts/coord/Axis>}\n     */\n    getAxes: function () {\n        return [this._radiusAxis, this._angleAxis];\n    },\n\n    /**\n     * Get axes by type of scale\n     * @param {string} scaleType\n     * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    getAxesByScale: function (scaleType) {\n        var axes = [];\n        var angleAxis = this._angleAxis;\n        var radiusAxis = this._radiusAxis;\n        angleAxis.scale.type === scaleType && axes.push(angleAxis);\n        radiusAxis.scale.type === scaleType && axes.push(radiusAxis);\n\n        return axes;\n    },\n\n    /**\n     * @return {module:echarts/coord/polar/AngleAxis}\n     */\n    getAngleAxis: function () {\n        return this._angleAxis;\n    },\n\n    /**\n     * @return {module:echarts/coord/polar/RadiusAxis}\n     */\n    getRadiusAxis: function () {\n        return this._radiusAxis;\n    },\n\n    /**\n     * @param {module:echarts/coord/polar/Axis}\n     * @return {module:echarts/coord/polar/Axis}\n     */\n    getOtherAxis: function (axis) {\n        var angleAxis = this._angleAxis;\n        return axis === angleAxis ? this._radiusAxis : angleAxis;\n    },\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/polar/Axis}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAngleAxis();\n    },\n\n    /**\n     * @param {string} [dim] 'radius' or 'angle' or 'auto' or null/undefined\n     * @return {Object} {baseAxes: [], otherAxes: []}\n     */\n    getTooltipAxes: function (dim) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? this.getAxis(dim) : this.getBaseAxis();\n        return {\n            baseAxes: [baseAxis],\n            otherAxes: [this.getOtherAxis(baseAxis)]\n        };\n    },\n\n    /**\n     * Convert a single data item to (x, y) point.\n     * Parameter data is an array which the first element is radius and the second is angle\n     * @param {Array.<number>} data\n     * @param {boolean} [clamp=false]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, clamp) {\n        return this.coordToPoint([\n            this._radiusAxis.dataToRadius(data[0], clamp),\n            this._angleAxis.dataToAngle(data[1], clamp)\n        ]);\n    },\n\n    /**\n     * Convert a (x, y) point to data\n     * @param {Array.<number>} point\n     * @param {boolean} [clamp=false]\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, clamp) {\n        var coord = this.pointToCoord(point);\n        return [\n            this._radiusAxis.radiusToData(coord[0], clamp),\n            this._angleAxis.angleToData(coord[1], clamp)\n        ];\n    },\n\n    /**\n     * Convert a (x, y) point to (radius, angle) coord\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToCoord: function (point) {\n        var dx = point[0] - this.cx;\n        var dy = point[1] - this.cy;\n        var angleAxis = this.getAngleAxis();\n        var extent = angleAxis.getExtent();\n        var minAngle = Math.min(extent[0], extent[1]);\n        var maxAngle = Math.max(extent[0], extent[1]);\n        // Fix fixed extent in polarCreator\n        // FIXME\n        angleAxis.inverse\n            ? (minAngle = maxAngle - 360)\n            : (maxAngle = minAngle + 360);\n\n        var radius = Math.sqrt(dx * dx + dy * dy);\n        dx /= radius;\n        dy /= radius;\n\n        var radian = Math.atan2(-dy, dx) / Math.PI * 180;\n\n        // move to angleExtent\n        var dir = radian < minAngle ? 1 : -1;\n        while (radian < minAngle || radian > maxAngle) {\n            radian += dir * 360;\n        }\n\n        return [radius, radian];\n    },\n\n    /**\n     * Convert a (radius, angle) coord to (x, y) point\n     * @param {Array.<number>} coord\n     * @return {Array.<number>}\n     */\n    coordToPoint: function (coord) {\n        var radius = coord[0];\n        var radian = coord[1] / 180 * Math.PI;\n        var x = Math.cos(radian) * radius + this.cx;\n        // Inverse the y\n        var y = -Math.sin(radian) * radius + this.cy;\n\n        return [x, y];\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PolarAxisModel = ComponentModel.extend({\n\n    type: 'polarAxis',\n\n    /**\n     * @type {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'polar',\n            index: this.option.polarIndex,\n            id: this.option.polarId\n        })[0];\n    }\n\n});\n\nmerge(PolarAxisModel.prototype, axisModelCommonMixin);\n\nvar polarAxisDefaultExtendedOption = {\n    angle: {\n        // polarIndex: 0,\n        // polarId: '',\n\n        startAngle: 90,\n\n        clockwise: true,\n\n        splitNumber: 12,\n\n        axisLabel: {\n            rotate: false\n        }\n    },\n    radius: {\n        // polarIndex: 0,\n        // polarId: '',\n\n        splitNumber: 5\n    }\n};\n\nfunction getAxisType$3(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\naxisModelCreator('angle', PolarAxisModel, getAxisType$3, polarAxisDefaultExtendedOption.angle);\naxisModelCreator('radius', PolarAxisModel, getAxisType$3, polarAxisDefaultExtendedOption.radius);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'polar',\n\n    dependencies: ['polarAxis', 'angleAxis'],\n\n    /**\n     * @type {module:echarts/coord/polar/Polar}\n     */\n    coordinateSystem: null,\n\n    /**\n     * @param {string} axisType\n     * @return {module:echarts/coord/polar/AxisModel}\n     */\n    findAxisModel: function (axisType) {\n        var foundAxisModel;\n        var ecModel = this.ecModel;\n\n        ecModel.eachComponent(axisType, function (axisModel) {\n            if (axisModel.getCoordSysModel() === this) {\n                foundAxisModel = axisModel;\n            }\n        }, this);\n        return foundAxisModel;\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        center: ['50%', '50%'],\n\n        radius: '80%'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Axis scale\n\n/**\n * Resize method bound to the polar\n * @param {module:echarts/coord/polar/PolarModel} polarModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction resizePolar(polar, polarModel, api) {\n    var center = polarModel.get('center');\n    var width = api.getWidth();\n    var height = api.getHeight();\n\n    polar.cx = parsePercent$1(center[0], width);\n    polar.cy = parsePercent$1(center[1], height);\n\n    var radiusAxis = polar.getRadiusAxis();\n    var size = Math.min(width, height) / 2;\n    var radius = parsePercent$1(polarModel.get('radius'), size);\n    radiusAxis.inverse\n        ? radiusAxis.setExtent(radius, 0)\n        : radiusAxis.setExtent(0, radius);\n}\n\n/**\n * Update polar\n */\nfunction updatePolarScale(ecModel, api) {\n    var polar = this;\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n    // Reset scale\n    angleAxis.scale.setExtent(Infinity, -Infinity);\n    radiusAxis.scale.setExtent(Infinity, -Infinity);\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.coordinateSystem === polar) {\n            var data = seriesModel.getData();\n            each$1(data.mapDimension('radius', true), function (dim) {\n                radiusAxis.scale.unionExtentFromData(\n                    data, getStackedDimension(data, dim)\n                );\n            });\n            each$1(data.mapDimension('angle', true), function (dim) {\n                angleAxis.scale.unionExtentFromData(\n                    data, getStackedDimension(data, dim)\n                );\n            });\n        }\n    });\n\n    niceScaleExtent(angleAxis.scale, angleAxis.model);\n    niceScaleExtent(radiusAxis.scale, radiusAxis.model);\n\n    // Fix extent of category angle axis\n    if (angleAxis.type === 'category' && !angleAxis.onBand) {\n        var extent = angleAxis.getExtent();\n        var diff = 360 / angleAxis.scale.count();\n        angleAxis.inverse ? (extent[1] += diff) : (extent[1] -= diff);\n        angleAxis.setExtent(extent[0], extent[1]);\n    }\n}\n\n/**\n * Set common axis properties\n * @param {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n * @param {module:echarts/coord/polar/AxisModel}\n * @inner\n */\nfunction setAxis(axis, axisModel) {\n    axis.type = axisModel.get('type');\n    axis.scale = createScaleByModel(axisModel);\n    axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category';\n    axis.inverse = axisModel.get('inverse');\n\n    if (axisModel.mainType === 'angleAxis') {\n        axis.inverse ^= axisModel.get('clockwise');\n        var startAngle = axisModel.get('startAngle');\n        axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360));\n    }\n\n    // Inject axis instance\n    axisModel.axis = axis;\n    axis.model = axisModel;\n}\n\n\nvar polarCreator = {\n\n    dimensions: Polar.prototype.dimensions,\n\n    create: function (ecModel, api) {\n        var polarList = [];\n        ecModel.eachComponent('polar', function (polarModel, idx) {\n            var polar = new Polar(idx);\n            // Inject resize and update method\n            polar.update = updatePolarScale;\n\n            var radiusAxis = polar.getRadiusAxis();\n            var angleAxis = polar.getAngleAxis();\n\n            var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n            var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n            setAxis(radiusAxis, radiusAxisModel);\n            setAxis(angleAxis, angleAxisModel);\n\n            resizePolar(polar, polarModel, api);\n\n            polarList.push(polar);\n\n            polarModel.coordinateSystem = polar;\n            polar.model = polarModel;\n        });\n        // Inject coordinateSystem to series\n        ecModel.eachSeries(function (seriesModel) {\n            if (seriesModel.get('coordinateSystem') === 'polar') {\n                var polarModel = ecModel.queryComponents({\n                    mainType: 'polar',\n                    index: seriesModel.get('polarIndex'),\n                    id: seriesModel.get('polarId')\n                })[0];\n\n                if (__DEV__) {\n                    if (!polarModel) {\n                        throw new Error(\n                            'Polar \"' + retrieve(\n                                seriesModel.get('polarIndex'),\n                                seriesModel.get('polarId'),\n                                0\n                            ) + '\" not found'\n                        );\n                    }\n                }\n                seriesModel.coordinateSystem = polarModel.coordinateSystem;\n            }\n        });\n\n        return polarList;\n    }\n};\n\nCoordinateSystemManager.register('polar', polarCreator);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar elementList$1 = ['axisLine', 'axisLabel', 'axisTick', 'splitLine', 'splitArea'];\n\nfunction getAxisLineShape(polar, rExtent, angle) {\n    rExtent[1] > rExtent[0] && (rExtent = rExtent.slice().reverse());\n    var start = polar.coordToPoint([rExtent[0], angle]);\n    var end = polar.coordToPoint([rExtent[1], angle]);\n\n    return {\n        x1: start[0],\n        y1: start[1],\n        x2: end[0],\n        y2: end[1]\n    };\n}\n\nfunction getRadiusIdx(polar) {\n    var radiusAxis = polar.getRadiusAxis();\n    return radiusAxis.inverse ? 0 : 1;\n}\n\n// Remove the last tick which will overlap the first tick\nfunction fixAngleOverlap(list) {\n    var firstItem = list[0];\n    var lastItem = list[list.length - 1];\n    if (firstItem\n        && lastItem\n        && Math.abs(Math.abs(firstItem.coord - lastItem.coord) - 360) < 1e-4\n    ) {\n        list.pop();\n    }\n}\n\nAxisView.extend({\n\n    type: 'angleAxis',\n\n    axisPointerClass: 'PolarAxisPointer',\n\n    render: function (angleAxisModel, ecModel) {\n        this.group.removeAll();\n        if (!angleAxisModel.get('show')) {\n            return;\n        }\n\n        var angleAxis = angleAxisModel.axis;\n        var polar = angleAxis.polar;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n\n        var ticksAngles = angleAxis.getTicksCoords();\n        var labels = map(angleAxis.getViewLabels(), function (labelItem) {\n            var labelItem = clone(labelItem);\n            labelItem.coord = angleAxis.dataToCoord(labelItem.tickValue);\n            return labelItem;\n        });\n\n        fixAngleOverlap(labels);\n        fixAngleOverlap(ticksAngles);\n\n        each$1(elementList$1, function (name) {\n            if (angleAxisModel.get(name + '.show')\n                && (!angleAxis.scale.isBlank() || name === 'axisLine')\n            ) {\n                this['_' + name](angleAxisModel, polar, ticksAngles, radiusExtent, labels);\n            }\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');\n\n        var circle = new Circle({\n            shape: {\n                cx: polar.cx,\n                cy: polar.cy,\n                r: radiusExtent[getRadiusIdx(polar)]\n            },\n            style: lineStyleModel.getLineStyle(),\n            z2: 1,\n            silent: true\n        });\n        circle.style.fill = null;\n\n        this.group.add(circle);\n    },\n\n    /**\n     * @private\n     */\n    _axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var tickModel = angleAxisModel.getModel('axisTick');\n\n        var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');\n        var radius = radiusExtent[getRadiusIdx(polar)];\n\n        var lines = map(ticksAngles, function (tickAngleItem) {\n            return new Line({\n                shape: getAxisLineShape(polar, [radius, radius + tickLen], tickAngleItem.coord)\n            });\n        });\n        this.group.add(mergePath(\n            lines, {\n                style: defaults(\n                    tickModel.getModel('lineStyle').getLineStyle(),\n                    {\n                        stroke: angleAxisModel.get('axisLine.lineStyle.color')\n                    }\n                )\n            }\n        ));\n    },\n\n    /**\n     * @private\n     */\n    _axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent, labels) {\n        var rawCategoryData = angleAxisModel.getCategories(true);\n\n        var commonLabelModel = angleAxisModel.getModel('axisLabel');\n\n        var labelMargin = commonLabelModel.get('margin');\n\n        // Use length of ticksAngles because it may remove the last tick to avoid overlapping\n        each$1(labels, function (labelItem, idx) {\n            var labelModel = commonLabelModel;\n            var tickValue = labelItem.tickValue;\n\n            var r = radiusExtent[getRadiusIdx(polar)];\n            var p = polar.coordToPoint([r + labelMargin, labelItem.coord]);\n            var cx = polar.cx;\n            var cy = polar.cy;\n\n            var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3\n                ? 'center' : (p[0] > cx ? 'left' : 'right');\n            var labelTextVerticalAlign = Math.abs(p[1] - cy) / r < 0.3\n                ? 'middle' : (p[1] > cy ? 'top' : 'bottom');\n\n            if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n                labelModel = new Model(\n                    rawCategoryData[tickValue].textStyle, commonLabelModel, commonLabelModel.ecModel\n                );\n            }\n\n            var textEl = new Text({silent: true});\n            this.group.add(textEl);\n            setTextStyle(textEl.style, labelModel, {\n                x: p[0],\n                y: p[1],\n                textFill: labelModel.getTextColor() || angleAxisModel.get('axisLine.lineStyle.color'),\n                text: labelItem.formattedLabel,\n                textAlign: labelTextAlign,\n                textVerticalAlign: labelTextVerticalAlign\n            });\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var splitLineModel = angleAxisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n        var lineCount = 0;\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var splitLines = [];\n\n        for (var i = 0; i < ticksAngles.length; i++) {\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Line({\n                shape: getAxisLineShape(polar, radiusExtent, ticksAngles[i].coord)\n            }));\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitLines.length; i++) {\n            this.group.add(mergePath(splitLines[i], {\n                style: defaults({\n                    stroke: lineColors[i % lineColors.length]\n                }, lineStyleModel.getLineStyle()),\n                silent: true,\n                z: angleAxisModel.get('z')\n            }));\n        }\n    },\n\n    /**\n     * @private\n     */\n    _splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        if (!ticksAngles.length) {\n            return;\n        }\n\n        var splitAreaModel = angleAxisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n        var lineCount = 0;\n\n        areaColors = areaColors instanceof Array ? areaColors : [areaColors];\n\n        var splitAreas = [];\n\n        var RADIAN = Math.PI / 180;\n        var prevAngle = -ticksAngles[0].coord * RADIAN;\n        var r0 = Math.min(radiusExtent[0], radiusExtent[1]);\n        var r1 = Math.max(radiusExtent[0], radiusExtent[1]);\n\n        var clockwise = angleAxisModel.get('clockwise');\n\n        for (var i = 1; i < ticksAngles.length; i++) {\n            var colorIndex = (lineCount++) % areaColors.length;\n            splitAreas[colorIndex] = splitAreas[colorIndex] || [];\n            splitAreas[colorIndex].push(new Sector({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r0: r0,\n                    r: r1,\n                    startAngle: prevAngle,\n                    endAngle: -ticksAngles[i].coord * RADIAN,\n                    clockwise: clockwise\n                },\n                silent: true\n            }));\n            prevAngle = -ticksAngles[i].coord * RADIAN;\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitAreas.length; i++) {\n            this.group.add(mergePath(splitAreas[i], {\n                style: defaults({\n                    fill: areaColors[i % areaColors.length]\n                }, areaStyleModel.getAreaStyle()),\n                silent: true\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs$3 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs$1 = [\n    'splitLine', 'splitArea'\n];\n\nAxisView.extend({\n\n    type: 'radiusAxis',\n\n    axisPointerClass: 'PolarAxisPointer',\n\n    render: function (radiusAxisModel, ecModel) {\n        this.group.removeAll();\n        if (!radiusAxisModel.get('show')) {\n            return;\n        }\n        var radiusAxis = radiusAxisModel.axis;\n        var polar = radiusAxis.polar;\n        var angleAxis = polar.getAngleAxis();\n        var ticksCoords = radiusAxis.getTicksCoords();\n        var axisAngle = angleAxis.getExtent()[0];\n        var radiusExtent = radiusAxis.getExtent();\n\n        var layout = layoutAxis(polar, radiusAxisModel, axisAngle);\n        var axisBuilder = new AxisBuilder(radiusAxisModel, layout);\n        each$1(axisBuilderAttrs$3, axisBuilder.add, axisBuilder);\n        this.group.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs$1, function (name) {\n            if (radiusAxisModel.get(name + '.show') && !radiusAxis.scale.isBlank()) {\n                this['_' + name](radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords);\n            }\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {\n        var splitLineModel = radiusAxisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n        var lineCount = 0;\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var splitLines = [];\n\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Circle({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r: ticksCoords[i].coord\n                },\n                silent: true\n            }));\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitLines.length; i++) {\n            this.group.add(mergePath(splitLines[i], {\n                style: defaults({\n                    stroke: lineColors[i % lineColors.length],\n                    fill: null\n                }, lineStyleModel.getLineStyle()),\n                silent: true\n            }));\n        }\n    },\n\n    /**\n     * @private\n     */\n    _splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        var splitAreaModel = radiusAxisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n        var lineCount = 0;\n\n        areaColors = areaColors instanceof Array ? areaColors : [areaColors];\n\n        var splitAreas = [];\n\n        var prevRadius = ticksCoords[0].coord;\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var colorIndex = (lineCount++) % areaColors.length;\n            splitAreas[colorIndex] = splitAreas[colorIndex] || [];\n            splitAreas[colorIndex].push(new Sector({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r0: prevRadius,\n                    r: ticksCoords[i].coord,\n                    startAngle: 0,\n                    endAngle: Math.PI * 2\n                },\n                silent: true\n            }));\n            prevRadius = ticksCoords[i].coord;\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitAreas.length; i++) {\n            this.group.add(mergePath(splitAreas[i], {\n                style: defaults({\n                    fill: areaColors[i % areaColors.length]\n                }, areaStyleModel.getAreaStyle()),\n                silent: true\n            }));\n        }\n    }\n});\n\n/**\n * @inner\n */\nfunction layoutAxis(polar, radiusAxisModel, axisAngle) {\n    return {\n        position: [polar.cx, polar.cy],\n        rotation: axisAngle / 180 * Math.PI,\n        labelDirection: -1,\n        tickDirection: -1,\n        nameDirection: 1,\n        labelRotate: radiusAxisModel.getModel('axisLabel').get('rotate'),\n        // Over splitLine and splitArea\n        z2: 1\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PolarAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n\n        if (axis.dim === 'angle') {\n            this.animationThreshold = Math.PI / 18;\n        }\n\n        var polar = axis.polar;\n        var otherAxis = polar.getOtherAxis(axis);\n        var otherExtent = otherAxis.getExtent();\n\n        var coordValue;\n        coordValue = axis['dataTo' + capitalFirst(axis.dim)](value);\n\n        var axisPointerType = axisPointerModel.get('type');\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder$2[axisPointerType](\n                axis, polar, coordValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var labelMargin = axisPointerModel.get('label.margin');\n        var labelPos = getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin);\n        buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos);\n    }\n\n    // Do not support handle, utill any user requires it.\n\n});\n\nfunction getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin) {\n    var axis = axisModel.axis;\n    var coord = axis.dataToCoord(value);\n    var axisAngle = polar.getAngleAxis().getExtent()[0];\n    axisAngle = axisAngle / 180 * Math.PI;\n    var radiusExtent = polar.getRadiusAxis().getExtent();\n    var position;\n    var align;\n    var verticalAlign;\n\n    if (axis.dim === 'radius') {\n        var transform = create$1();\n        rotate(transform, transform, axisAngle);\n        translate(transform, transform, [polar.cx, polar.cy]);\n        position = applyTransform$1([coord, -labelMargin], transform);\n\n        var labelRotation = axisModel.getModel('axisLabel').get('rotate') || 0;\n        var labelLayout = AxisBuilder.innerTextLayout(\n            axisAngle, labelRotation * Math.PI / 180, -1\n        );\n        align = labelLayout.textAlign;\n        verticalAlign = labelLayout.textVerticalAlign;\n    }\n    else { // angle axis\n        var r = radiusExtent[1];\n        position = polar.coordToPoint([r + labelMargin, coord]);\n        var cx = polar.cx;\n        var cy = polar.cy;\n        align = Math.abs(position[0] - cx) / r < 0.3\n            ? 'center' : (position[0] > cx ? 'left' : 'right');\n        verticalAlign = Math.abs(position[1] - cy) / r < 0.3\n            ? 'middle' : (position[1] > cy ? 'top' : 'bottom');\n    }\n\n    return {\n        position: position,\n        align: align,\n        verticalAlign: verticalAlign\n    };\n}\n\n\nvar pointerShapeBuilder$2 = {\n\n    line: function (axis, polar, coordValue, otherExtent, elStyle) {\n        return axis.dim === 'angle'\n            ? {\n                type: 'Line',\n                shape: makeLineShape(\n                    polar.coordToPoint([otherExtent[0], coordValue]),\n                    polar.coordToPoint([otherExtent[1], coordValue])\n                )\n            }\n            : {\n                type: 'Circle',\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r: coordValue\n                }\n            };\n    },\n\n    shadow: function (axis, polar, coordValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var radian = Math.PI / 180;\n\n        return axis.dim === 'angle'\n            ? {\n                type: 'Sector',\n                shape: makeSectorShape(\n                    polar.cx, polar.cy,\n                    otherExtent[0], otherExtent[1],\n                    // In ECharts y is negative if angle is positive\n                    (-coordValue - bandWidth / 2) * radian,\n                    (-coordValue + bandWidth / 2) * radian\n                )\n            }\n            : {\n                type: 'Sector',\n                shape: makeSectorShape(\n                    polar.cx, polar.cy,\n                    coordValue - bandWidth / 2,\n                    coordValue + bandWidth / 2,\n                    0, Math.PI * 2\n                )\n            };\n    }\n};\n\nAxisView.registerAxisPointerClass('PolarAxisPointer', PolarAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// For reducing size of echarts.min, barLayoutPolar is required by polar.\nregisterLayout(curry(barLayoutPolar, 'bar'));\n\n// Polar view\nextendComponentView({\n    type: 'polar'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GeoModel = ComponentModel.extend({\n\n    type: 'geo',\n\n    /**\n     * @type {module:echarts/coord/geo/Geo}\n     */\n    coordinateSystem: null,\n\n    layoutMode: 'box',\n\n    init: function (option) {\n        ComponentModel.prototype.init.apply(this, arguments);\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n    },\n\n    optionUpdated: function () {\n        var option = this.option;\n        var self = this;\n\n        option.regions = geoCreator.getFilledRegions(option.regions, option.map, option.nameMap);\n\n        this._optionModelMap = reduce(option.regions || [], function (optionModelMap, regionOpt) {\n            if (regionOpt.name) {\n                optionModelMap.set(regionOpt.name, new Model(regionOpt, self));\n            }\n            return optionModelMap;\n        }, createHashMap());\n\n        this.updateSelectedMap(option.regions);\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        show: true,\n\n        left: 'center',\n\n        top: 'center',\n\n\n        // width:,\n        // height:,\n        // right\n        // bottom\n\n        // Aspect is width / height. Inited to be geoJson bbox aspect\n        // This parameter is used for scale this aspect\n        // If svg used, aspectScale is 1 by default.\n        // aspectScale: 0.75,\n        aspectScale: null,\n\n        ///// Layout with center and size\n        // If you wan't to put map in a fixed size box with right aspect ratio\n        // This two properties may more conveninet\n        // layoutCenter: [50%, 50%]\n        // layoutSize: 100\n\n        silent: false,\n\n        // Map type\n        map: '',\n\n        // Define left-top, right-bottom coords to control view\n        // For example, [ [180, 90], [-180, -90] ]\n        boundingCoords: null,\n\n        // Default on center of map\n        center: null,\n\n        zoom: 1,\n\n        scaleLimit: null,\n\n        // selectedMode: false\n\n        label: {\n            show: false,\n            color: '#000'\n        },\n\n        itemStyle: {\n            // color: 各异,\n            borderWidth: 0.5,\n            borderColor: '#444',\n            color: '#eee'\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                color: 'rgb(100,0,0)'\n            },\n            itemStyle: {\n                color: 'rgba(255,215,0,0.8)'\n            }\n        },\n\n        regions: []\n    },\n\n    /**\n     * Get model of region\n     * @param  {string} name\n     * @return {module:echarts/model/Model}\n     */\n    getRegionModel: function (name) {\n        return this._optionModelMap.get(name) || new Model(null, this, this.ecModel);\n    },\n\n    /**\n     * Format label\n     * @param {string} name Region name\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @return {string}\n     */\n    getFormattedLabel: function (name, status) {\n        var regionModel = this.getRegionModel(name);\n        var formatter = regionModel.get('label.' + status + '.formatter');\n        var params = {\n            name: name\n        };\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            return formatter.replace('{a}', name != null ? name : '');\n        }\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    }\n});\n\nmixin(GeoModel, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'geo',\n\n    init: function (ecModel, api) {\n        var mapDraw = new MapDraw(api, true);\n        this._mapDraw = mapDraw;\n\n        this.group.add(mapDraw.group);\n    },\n\n    render: function (geoModel, ecModel, api, payload) {\n        // Not render if it is an toggleSelect action from self\n        if (payload && payload.type === 'geoToggleSelect'\n            && payload.from === this.uid\n        ) {\n            return;\n        }\n\n        var mapDraw = this._mapDraw;\n        if (geoModel.get('show')) {\n            mapDraw.draw(geoModel, ecModel, api, this, payload);\n        }\n        else {\n            this._mapDraw.group.removeAll();\n        }\n\n        this.group.silent = geoModel.get('silent');\n    },\n\n    dispose: function () {\n        this._mapDraw && this._mapDraw.remove();\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeAction(method, actionInfo) {\n    actionInfo.update = 'updateView';\n    registerAction(actionInfo, function (payload, ecModel) {\n        var selected = {};\n\n        ecModel.eachComponent(\n            { mainType: 'geo', query: payload},\n            function (geoModel) {\n                geoModel[method](payload.name);\n                var geo = geoModel.coordinateSystem;\n                each$1(geo.regions, function (region) {\n                    selected[region.name] = geoModel.isSelected(region.name) || false;\n                });\n            }\n        );\n\n        return {\n            selected: selected,\n            name: payload.name\n        };\n    });\n}\n\nmakeAction('toggleSelected', {\n    type: 'geoToggleSelect',\n    event: 'geoselectchanged'\n});\nmakeAction('select', {\n    type: 'geoSelect',\n    event: 'geoselected'\n});\nmakeAction('unSelect', {\n    type: 'geoUnSelect',\n    event: 'geounselected'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_TOOLBOX_BTNS = ['rect', 'polygon', 'keep', 'clear'];\n\nvar preprocessor$1 = function (option, isNew) {\n    var brushComponents = option && option.brush;\n    if (!isArray(brushComponents)) {\n        brushComponents = brushComponents ? [brushComponents] : [];\n    }\n\n    if (!brushComponents.length) {\n        return;\n    }\n\n    var brushComponentSpecifiedBtns = [];\n\n    each$1(brushComponents, function (brushOpt) {\n        var tbs = brushOpt.hasOwnProperty('toolbox')\n            ? brushOpt.toolbox : [];\n\n        if (tbs instanceof Array) {\n            brushComponentSpecifiedBtns = brushComponentSpecifiedBtns.concat(tbs);\n        }\n    });\n\n    var toolbox = option && option.toolbox;\n\n    if (isArray(toolbox)) {\n        toolbox = toolbox[0];\n    }\n    if (!toolbox) {\n        toolbox = {feature: {}};\n        option.toolbox = [toolbox];\n    }\n\n    var toolboxFeature = (toolbox.feature || (toolbox.feature = {}));\n    var toolboxBrush = toolboxFeature.brush || (toolboxFeature.brush = {});\n    var brushTypes = toolboxBrush.type || (toolboxBrush.type = []);\n\n    brushTypes.push.apply(brushTypes, brushComponentSpecifiedBtns);\n\n    removeDuplicate(brushTypes);\n\n    if (isNew && !brushTypes.length) {\n        brushTypes.push.apply(brushTypes, DEFAULT_TOOLBOX_BTNS);\n    }\n};\n\nfunction removeDuplicate(arr) {\n    var map$$1 = {};\n    each$1(arr, function (val) {\n        map$$1[val] = 1;\n    });\n    arr.length = 0;\n    each$1(map$$1, function (flag, val) {\n        arr.push(val);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual solution, for consistent option specification.\n */\n\nvar each$19 = each$1;\n\nfunction hasKeys(obj) {\n    if (obj) {\n        for (var name in obj) {\n            if (obj.hasOwnProperty(name)) {\n                return true;\n            }\n        }\n    }\n}\n\n/**\n * @param {Object} option\n * @param {Array.<string>} stateList\n * @param {Function} [supplementVisualOption]\n * @return {Object} visualMappings <state, <visualType, module:echarts/visual/VisualMapping>>\n */\nfunction createVisualMappings(option, stateList, supplementVisualOption) {\n    var visualMappings = {};\n\n    each$19(stateList, function (state) {\n        var mappings = visualMappings[state] = createMappings();\n\n        each$19(option[state], function (visualData, visualType) {\n            if (!VisualMapping.isValidType(visualType)) {\n                return;\n            }\n            var mappingOption = {\n                type: visualType,\n                visual: visualData\n            };\n            supplementVisualOption && supplementVisualOption(mappingOption, state);\n            mappings[visualType] = new VisualMapping(mappingOption);\n\n            // Prepare a alpha for opacity, for some case that opacity\n            // is not supported, such as rendering using gradient color.\n            if (visualType === 'opacity') {\n                mappingOption = clone(mappingOption);\n                mappingOption.type = 'colorAlpha';\n                mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption);\n            }\n        });\n    });\n\n    return visualMappings;\n\n    function createMappings() {\n        var Creater = function () {};\n        // Make sure hidden fields will not be visited by\n        // object iteration (with hasOwnProperty checking).\n        Creater.prototype.__hidden = Creater.prototype;\n        var obj = new Creater();\n        return obj;\n    }\n}\n\n/**\n * @param {Object} thisOption\n * @param {Object} newOption\n * @param {Array.<string>} keys\n */\nfunction replaceVisualOption(thisOption, newOption, keys) {\n    // Visual attributes merge is not supported, otherwise it\n    // brings overcomplicated merge logic. See #2853. So if\n    // newOption has anyone of these keys, all of these keys\n    // will be reset. Otherwise, all keys remain.\n    var has;\n    each$1(keys, function (key) {\n        if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {\n            has = true;\n        }\n    });\n    has && each$1(keys, function (key) {\n        if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {\n            thisOption[key] = clone(newOption[key]);\n        }\n        else {\n            delete thisOption[key];\n        }\n    });\n}\n\n/**\n * @param {Array.<string>} stateList\n * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>\n * @param {module:echarts/data/List} list\n * @param {Function} getValueState param: valueOrIndex, return: state.\n * @param {object} [scope] Scope for getValueState\n * @param {string} [dimension] Concrete dimension, if used.\n */\n// ???! handle brush?\nfunction applyVisual(stateList, visualMappings, data, getValueState, scope, dimension) {\n    var visualTypesMap = {};\n    each$1(stateList, function (state) {\n        var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);\n        visualTypesMap[state] = visualTypes;\n    });\n\n    var dataIndex;\n\n    function getVisual(key) {\n        return data.getItemVisual(dataIndex, key);\n    }\n\n    function setVisual(key, value) {\n        data.setItemVisual(dataIndex, key, value);\n    }\n\n    if (dimension == null) {\n        data.each(eachItem);\n    }\n    else {\n        data.each([dimension], eachItem);\n    }\n\n    function eachItem(valueOrIndex, index) {\n        dataIndex = dimension == null ? valueOrIndex : index;\n\n        var rawDataItem = data.getRawDataItem(dataIndex);\n        // Consider performance\n        if (rawDataItem && rawDataItem.visualMap === false) {\n            return;\n        }\n\n        var valueState = getValueState.call(scope, valueOrIndex);\n        var mappings = visualMappings[valueState];\n        var visualTypes = visualTypesMap[valueState];\n\n        for (var i = 0, len = visualTypes.length; i < len; i++) {\n            var type = visualTypes[i];\n            mappings[type] && mappings[type].applyVisual(\n                valueOrIndex, getVisual, setVisual\n            );\n        }\n    }\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Array.<string>} stateList\n * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>\n * @param {Function} getValueState param: valueOrIndex, return: state.\n * @param {number} [dim] dimension or dimension index.\n */\nfunction incrementalApplyVisual(stateList, visualMappings, getValueState, dim) {\n    var visualTypesMap = {};\n    each$1(stateList, function (state) {\n        var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);\n        visualTypesMap[state] = visualTypes;\n    });\n\n    function progress(params, data) {\n        if (dim != null) {\n            dim = data.getDimension(dim);\n        }\n\n        function getVisual(key) {\n            return data.getItemVisual(dataIndex, key);\n        }\n\n        function setVisual(key, value) {\n            data.setItemVisual(dataIndex, key, value);\n        }\n\n        var dataIndex;\n        while ((dataIndex = params.next()) != null) {\n            var rawDataItem = data.getRawDataItem(dataIndex);\n\n            // Consider performance\n            if (rawDataItem && rawDataItem.visualMap === false) {\n                continue;\n            }\n\n            var value = dim != null\n                ? data.get(dim, dataIndex, true)\n                : dataIndex;\n\n            var valueState = getValueState(value);\n            var mappings = visualMappings[valueState];\n            var visualTypes = visualTypesMap[valueState];\n\n            for (var i = 0, len = visualTypes.length; i < len; i++) {\n                var type = visualTypes[i];\n                mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);\n            }\n        }\n    }\n\n    return {progress: progress};\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Key of the first level is brushType: `line`, `rect`, `polygon`.\n// Key of the second level is chart element type: `point`, `rect`.\n// See moudule:echarts/component/helper/BrushController\n// function param:\n//      {Object} itemLayout fetch from data.getItemLayout(dataIndex)\n//      {Object} selectors {point: selector, rect: selector, ...}\n//      {Object} area {range: [[], [], ..], boudingRect}\n// function return:\n//      {boolean} Whether in the given brush.\nvar selector = {\n    lineX: getLineSelectors(0),\n    lineY: getLineSelectors(1),\n    rect: {\n        point: function (itemLayout, selectors, area) {\n            return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]);\n        },\n        rect: function (itemLayout, selectors, area) {\n            return itemLayout && area.boundingRect.intersect(itemLayout);\n        }\n    },\n    polygon: {\n        point: function (itemLayout, selectors, area) {\n            return itemLayout\n                && area.boundingRect.contain(itemLayout[0], itemLayout[1])\n                && contain$1(area.range, itemLayout[0], itemLayout[1]);\n        },\n        rect: function (itemLayout, selectors, area) {\n            var points = area.range;\n\n            if (!itemLayout || points.length <= 1) {\n                return false;\n            }\n\n            var x = itemLayout.x;\n            var y = itemLayout.y;\n            var width = itemLayout.width;\n            var height = itemLayout.height;\n            var p = points[0];\n\n            if (contain$1(points, x, y)\n                || contain$1(points, x + width, y)\n                || contain$1(points, x, y + height)\n                || contain$1(points, x + width, y + height)\n                || BoundingRect.create(itemLayout).contain(p[0], p[1])\n                || lineIntersectPolygon(x, y, x + width, y, points)\n                || lineIntersectPolygon(x, y, x, y + height, points)\n                || lineIntersectPolygon(x + width, y, x + width, y + height, points)\n                || lineIntersectPolygon(x, y + height, x + width, y + height, points)\n            ) {\n                return true;\n            }\n        }\n    }\n};\n\nfunction getLineSelectors(xyIndex) {\n    var xy = ['x', 'y'];\n    var wh = ['width', 'height'];\n\n    return {\n        point: function (itemLayout, selectors, area) {\n            if (itemLayout) {\n                var range = area.range;\n                var p = itemLayout[xyIndex];\n                return inLineRange(p, range);\n            }\n        },\n        rect: function (itemLayout, selectors, area) {\n            if (itemLayout) {\n                var range = area.range;\n                var layoutRange = [\n                    itemLayout[xy[xyIndex]],\n                    itemLayout[xy[xyIndex]] + itemLayout[wh[xyIndex]]\n                ];\n                layoutRange[1] < layoutRange[0] && layoutRange.reverse();\n                return inLineRange(layoutRange[0], range)\n                    || inLineRange(layoutRange[1], range)\n                    || inLineRange(range[0], layoutRange)\n                    || inLineRange(range[1], layoutRange);\n            }\n        }\n    };\n}\n\nfunction inLineRange(p, range) {\n    return range[0] <= p && p <= range[1];\n}\n\nfunction lineIntersectPolygon(lx, ly, l2x, l2y, points) {\n    for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) {\n        var p = points[i];\n        if (lineIntersect(lx, ly, l2x, l2y, p[0], p[1], p2[0], p2[1])) {\n            return true;\n        }\n        p2 = p;\n    }\n}\n\n// Code from <http://blog.csdn.net/rickliuxiao/article/details/6259322> with some fix.\n// See <https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection>\nfunction lineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {\n    var delta = determinant(a2x - a1x, b1x - b2x, a2y - a1y, b1y - b2y);\n    if (nearZero(delta)) { // parallel\n        return false;\n    }\n    var namenda = determinant(b1x - a1x, b1x - b2x, b1y - a1y, b1y - b2y) / delta;\n    if (namenda < 0 || namenda > 1) {\n        return false;\n    }\n    var miu = determinant(a2x - a1x, b1x - a1x, a2y - a1y, b1y - a1y) / delta;\n    if (miu < 0 || miu > 1) {\n        return false;\n    }\n    return true;\n}\n\nfunction nearZero(val) {\n    return val <= (1e-6) && val >= -(1e-6);\n}\n\nfunction determinant(v1, v2, v3, v4) {\n    return v1 * v4 - v2 * v3;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$20 = each$1;\nvar indexOf$1 = indexOf;\nvar curry$5 = curry;\n\nvar COORD_CONVERTS = ['dataToPoint', 'pointToData'];\n\n// FIXME\n// how to genarialize to more coordinate systems.\nvar INCLUDE_FINDER_MAIN_TYPES = [\n    'grid', 'xAxis', 'yAxis', 'geo', 'graph',\n    'polar', 'radiusAxis', 'angleAxis', 'bmap'\n];\n\n/**\n * [option in constructor]:\n * {\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n * }\n *\n *\n * [targetInfo]:\n *\n * There can be multiple axes in a single targetInfo. Consider the case\n * of `grid` component, a targetInfo represents a grid which contains one or more\n * cartesian and one or more axes. And consider the case of parallel system,\n * which has multiple axes in a coordinate system.\n * Can be {\n *     panelId: ...,\n *     coordSys: <a representitive cartesian in grid (first cartesian by default)>,\n *     coordSyses: all cartesians.\n *     gridModel: <grid component>\n *     xAxes: correspond to coordSyses on index\n *     yAxes: correspond to coordSyses on index\n * }\n * or {\n *     panelId: ...,\n *     coordSys: <geo coord sys>\n *     coordSyses: [<geo coord sys>]\n *     geoModel: <geo component>\n * }\n *\n *\n * [panelOpt]:\n *\n * Make from targetInfo. Input to BrushController.\n * {\n *     panelId: ...,\n *     rect: ...\n * }\n *\n *\n * [area]:\n *\n * Generated by BrushController or user input.\n * {\n *     panelId: Used to locate coordInfo directly. If user inpput, no panelId.\n *     brushType: determine how to convert to/from coord('rect' or 'polygon' or 'lineX/Y').\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n *     range: pixel range.\n *     coordRange: representitive coord range (the first one of coordRanges).\n *     coordRanges: <Array> coord ranges, used in multiple cartesian in one grid.\n * }\n */\n\n/**\n * @param {Object} option contains Index/Id/Name of xAxis/yAxis/geo/grid\n *        Each can be {number|Array.<number>}. like: {xAxisIndex: [3, 4]}\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} [opt]\n * @param {Array.<string>} [opt.include] include coordinate system types.\n */\nfunction BrushTargetManager(option, ecModel, opt) {\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    var targetInfoList = this._targetInfoList = [];\n    var info = {};\n    var foundCpts = parseFinder$1(ecModel, option);\n\n    each$20(targetInfoBuilders, function (builder, type) {\n        if (!opt || !opt.include || indexOf$1(opt.include, type) >= 0) {\n            builder(foundCpts, targetInfoList, info);\n        }\n    });\n}\n\nvar proto$2 = BrushTargetManager.prototype;\n\nproto$2.setOutputRanges = function (areas, ecModel) {\n    this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        (area.coordRanges || (area.coordRanges = [])).push(coordRange);\n        // area.coordRange is the first of area.coordRanges\n        if (!area.coordRange) {\n            area.coordRange = coordRange;\n            // In 'category' axis, coord to pixel is not reversible, so we can not\n            // rebuild range by coordRange accrately, which may bring trouble when\n            // brushing only one item. So we use __rangeOffset to rebuilding range\n            // by coordRange. And this it only used in brush component so it is no\n            // need to be adapted to coordRanges.\n            var result = coordConvert[area.brushType](0, coordSys, coordRange);\n            area.__rangeOffset = {\n                offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]),\n                xyMinMax: result.xyMinMax\n            };\n        }\n    });\n};\n\nproto$2.matchOutputRanges = function (areas, ecModel, cb) {\n    each$20(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (targetInfo && targetInfo !== true) {\n            each$1(\n                targetInfo.coordSyses,\n                function (coordSys) {\n                    var result = coordConvert[area.brushType](1, coordSys, area.range);\n                    cb(area, result.values, coordSys, ecModel);\n                }\n            );\n        }\n    }, this);\n};\n\nproto$2.setInputRanges = function (areas, ecModel) {\n    each$20(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (__DEV__) {\n            assert$1(\n                !targetInfo || targetInfo === true || area.coordRange,\n                'coordRange must be specified when coord index specified.'\n            );\n            assert$1(\n                !targetInfo || targetInfo !== true || area.range,\n                'range must be specified in global brush.'\n            );\n        }\n\n        area.range = area.range || [];\n\n        // convert coordRange to global range and set panelId.\n        if (targetInfo && targetInfo !== true) {\n            area.panelId = targetInfo.panelId;\n            // (1) area.range shoule always be calculate from coordRange but does\n            // not keep its original value, for the sake of the dataZoom scenario,\n            // where area.coordRange remains unchanged but area.range may be changed.\n            // (2) Only support converting one coordRange to pixel range in brush\n            // component. So do not consider `coordRanges`.\n            // (3) About __rangeOffset, see comment above.\n            var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange);\n            var rangeOffset = area.__rangeOffset;\n            area.range = rangeOffset\n                ? diffProcessor[area.brushType](\n                    result.values,\n                    rangeOffset.offset,\n                    getScales(result.xyMinMax, rangeOffset.xyMinMax)\n                )\n                : result.values;\n        }\n    }, this);\n};\n\nproto$2.makePanelOpts = function (api, getDefaultBrushType) {\n    return map(this._targetInfoList, function (targetInfo) {\n        var rect = targetInfo.getPanelRect();\n        return {\n            panelId: targetInfo.panelId,\n            defaultBrushType: getDefaultBrushType && getDefaultBrushType(targetInfo),\n            clipPath: makeRectPanelClipPath(rect),\n            isTargetByCursor: makeRectIsTargetByCursor(\n                rect, api, targetInfo.coordSysModel\n            ),\n            getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect)\n        };\n    });\n};\n\nproto$2.controlSeries = function (area, seriesModel, ecModel) {\n    // Check whether area is bound in coord, and series do not belong to that coord.\n    // If do not do this check, some brush (like lineX) will controll all axes.\n    var targetInfo = this.findTargetInfo(area, ecModel);\n    return targetInfo === true || (\n        targetInfo && indexOf$1(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0\n    );\n};\n\n/**\n * If return Object, a coord found.\n * If reutrn true, global found.\n * Otherwise nothing found.\n *\n * @param {Object} area\n * @param {Array} targetInfoList\n * @return {Object|boolean}\n */\nproto$2.findTargetInfo = function (area, ecModel) {\n    var targetInfoList = this._targetInfoList;\n    var foundCpts = parseFinder$1(ecModel, area);\n\n    for (var i = 0; i < targetInfoList.length; i++) {\n        var targetInfo = targetInfoList[i];\n        var areaPanelId = area.panelId;\n        if (areaPanelId) {\n            if (targetInfo.panelId === areaPanelId) {\n                return targetInfo;\n            }\n        }\n        else {\n            for (var i = 0; i < targetInfoMatchers.length; i++) {\n                if (targetInfoMatchers[i](foundCpts, targetInfo)) {\n                    return targetInfo;\n                }\n            }\n        }\n    }\n\n    return true;\n};\n\nfunction formatMinMax(minMax) {\n    minMax[0] > minMax[1] && minMax.reverse();\n    return minMax;\n}\n\nfunction parseFinder$1(ecModel, option) {\n    return parseFinder(\n        ecModel, option, {includeMainTypes: INCLUDE_FINDER_MAIN_TYPES}\n    );\n}\n\nvar targetInfoBuilders = {\n\n    grid: function (foundCpts, targetInfoList) {\n        var xAxisModels = foundCpts.xAxisModels;\n        var yAxisModels = foundCpts.yAxisModels;\n        var gridModels = foundCpts.gridModels;\n        // Remove duplicated.\n        var gridModelMap = createHashMap();\n        var xAxesHas = {};\n        var yAxesHas = {};\n\n        if (!xAxisModels && !yAxisModels && !gridModels) {\n            return;\n        }\n\n        each$20(xAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n        });\n        each$20(yAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            yAxesHas[gridModel.id] = true;\n        });\n        each$20(gridModels, function (gridModel) {\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n            yAxesHas[gridModel.id] = true;\n        });\n\n        gridModelMap.each(function (gridModel) {\n            var grid = gridModel.coordinateSystem;\n            var cartesians = [];\n\n            each$20(grid.getCartesians(), function (cartesian, index) {\n                if (indexOf$1(xAxisModels, cartesian.getAxis('x').model) >= 0\n                    || indexOf$1(yAxisModels, cartesian.getAxis('y').model) >= 0\n                ) {\n                    cartesians.push(cartesian);\n                }\n            });\n            targetInfoList.push({\n                panelId: 'grid--' + gridModel.id,\n                gridModel: gridModel,\n                coordSysModel: gridModel,\n                // Use the first one as the representitive coordSys.\n                coordSys: cartesians[0],\n                coordSyses: cartesians,\n                getPanelRect: panelRectBuilder.grid,\n                xAxisDeclared: xAxesHas[gridModel.id],\n                yAxisDeclared: yAxesHas[gridModel.id]\n            });\n        });\n    },\n\n    geo: function (foundCpts, targetInfoList) {\n        each$20(foundCpts.geoModels, function (geoModel) {\n            var coordSys = geoModel.coordinateSystem;\n            targetInfoList.push({\n                panelId: 'geo--' + geoModel.id,\n                geoModel: geoModel,\n                coordSysModel: geoModel,\n                coordSys: coordSys,\n                coordSyses: [coordSys],\n                getPanelRect: panelRectBuilder.geo\n            });\n        });\n    }\n};\n\nvar targetInfoMatchers = [\n\n    // grid\n    function (foundCpts, targetInfo) {\n        var xAxisModel = foundCpts.xAxisModel;\n        var yAxisModel = foundCpts.yAxisModel;\n        var gridModel = foundCpts.gridModel;\n\n        !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model);\n        !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model);\n\n        return gridModel && gridModel === targetInfo.gridModel;\n    },\n\n    // geo\n    function (foundCpts, targetInfo) {\n        var geoModel = foundCpts.geoModel;\n        return geoModel && geoModel === targetInfo.geoModel;\n    }\n];\n\nvar panelRectBuilder = {\n\n    grid: function () {\n        // grid is not Transformable.\n        return this.coordSys.grid.getRect().clone();\n    },\n\n    geo: function () {\n        var coordSys = this.coordSys;\n        var rect = coordSys.getBoundingRect().clone();\n        // geo roam and zoom transform\n        rect.applyTransform(getTransform(coordSys));\n        return rect;\n    }\n};\n\nvar coordConvert = {\n\n    lineX: curry$5(axisConvert, 0),\n\n    lineY: curry$5(axisConvert, 1),\n\n    rect: function (to, coordSys, rangeOrCoordRange) {\n        var xminymin = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]]);\n        var xmaxymax = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]]);\n        var values = [\n            formatMinMax([xminymin[0], xmaxymax[0]]),\n            formatMinMax([xminymin[1], xmaxymax[1]])\n        ];\n        return {values: values, xyMinMax: values};\n    },\n\n    polygon: function (to, coordSys, rangeOrCoordRange) {\n        var xyMinMax = [[Infinity, -Infinity], [Infinity, -Infinity]];\n        var values = map(rangeOrCoordRange, function (item) {\n            var p = coordSys[COORD_CONVERTS[to]](item);\n            xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]);\n            xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]);\n            xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]);\n            xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]);\n            return p;\n        });\n        return {values: values, xyMinMax: xyMinMax};\n    }\n};\n\nfunction axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) {\n    if (__DEV__) {\n        assert$1(\n            coordSys.type === 'cartesian2d',\n            'lineX/lineY brush is available only in cartesian2d.'\n        );\n    }\n\n    var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]);\n    var values = formatMinMax(map([0, 1], function (i) {\n        return to\n            ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]))\n            : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i]));\n    }));\n    var xyMinMax = [];\n    xyMinMax[axisNameIndex] = values;\n    xyMinMax[1 - axisNameIndex] = [NaN, NaN];\n\n    return {values: values, xyMinMax: xyMinMax};\n}\n\nvar diffProcessor = {\n    lineX: curry$5(axisDiffProcessor, 0),\n\n    lineY: curry$5(axisDiffProcessor, 1),\n\n    rect: function (values, refer, scales) {\n        return [\n            [values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]],\n            [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]\n        ];\n    },\n\n    polygon: function (values, refer, scales) {\n        return map(values, function (item, idx) {\n            return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];\n        });\n    }\n};\n\nfunction axisDiffProcessor(axisNameIndex, values, refer, scales) {\n    return [\n        values[0] - scales[axisNameIndex] * refer[0],\n        values[1] - scales[axisNameIndex] * refer[1]\n    ];\n}\n\n// We have to process scale caused by dataZoom manually,\n// although it might be not accurate.\nfunction getScales(xyMinMaxCurr, xyMinMaxOrigin) {\n    var sizeCurr = getSize(xyMinMaxCurr);\n    var sizeOrigin = getSize(xyMinMaxOrigin);\n    var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]];\n    isNaN(scales[0]) && (scales[0] = 1);\n    isNaN(scales[1]) && (scales[1] = 1);\n    return scales;\n}\n\nfunction getSize(xyMinMax) {\n    return xyMinMax\n        ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]]\n        : [NaN, NaN];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar STATE_LIST = ['inBrush', 'outOfBrush'];\nvar DISPATCH_METHOD = '__ecBrushSelect';\nvar DISPATCH_FLAG = '__ecInBrushSelectEvent';\nvar PRIORITY_BRUSH = PRIORITY.VISUAL.BRUSH;\n\n/**\n * Layout for visual, the priority higher than other layout, and before brush visual.\n */\nregisterLayout(PRIORITY_BRUSH, function (ecModel, api, payload) {\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel) {\n\n        payload && payload.type === 'takeGlobalCursor' && brushModel.setBrushOption(\n            payload.key === 'brush' ? payload.brushOption : {brushType: false}\n        );\n\n        var brushTargetManager = brushModel.brushTargetManager = new BrushTargetManager(brushModel.option, ecModel);\n\n        brushTargetManager.setInputRanges(brushModel.areas, ecModel);\n    });\n});\n\n/**\n * Register the visual encoding if this modules required.\n */\nregisterVisual(PRIORITY_BRUSH, function (ecModel, api, payload) {\n\n    var brushSelected = [];\n    var throttleType;\n    var throttleDelay;\n\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel, brushIndex) {\n\n        var thisBrushSelected = {\n            brushId: brushModel.id,\n            brushIndex: brushIndex,\n            brushName: brushModel.name,\n            areas: clone(brushModel.areas),\n            selected: []\n        };\n        // Every brush component exists in event params, convenient\n        // for user to find by index.\n        brushSelected.push(thisBrushSelected);\n\n        var brushOption = brushModel.option;\n        var brushLink = brushOption.brushLink;\n        var linkedSeriesMap = [];\n        var selectedDataIndexForLink = [];\n        var rangeInfoBySeries = [];\n        var hasBrushExists = 0;\n\n        if (!brushIndex) { // Only the first throttle setting works.\n            throttleType = brushOption.throttleType;\n            throttleDelay = brushOption.throttleDelay;\n        }\n\n        // Add boundingRect and selectors to range.\n        var areas = map(brushModel.areas, function (area) {\n            return bindSelector(\n                defaults(\n                    {boundingRect: boundingRectBuilders[area.brushType](area)},\n                    area\n                )\n            );\n        });\n\n        var visualMappings = createVisualMappings(\n            brushModel.option, STATE_LIST, function (mappingOption) {\n                mappingOption.mappingMethod = 'fixed';\n            }\n        );\n\n        isArray(brushLink) && each$1(brushLink, function (seriesIndex) {\n            linkedSeriesMap[seriesIndex] = 1;\n        });\n\n        function linkOthers(seriesIndex) {\n            return brushLink === 'all' || linkedSeriesMap[seriesIndex];\n        }\n\n        // If no supported brush or no brush on the series,\n        // all visuals should be in original state.\n        function brushed(rangeInfoList) {\n            return !!rangeInfoList.length;\n        }\n\n        /**\n         * Logic for each series: (If the logic has to be modified one day, do it carefully!)\n         *\n         * ( brushed ┬ && ┬hasBrushExist ┬ && linkOthers  ) => StepA: ┬record, ┬ StepB: ┬visualByRecord.\n         *   !brushed┘    ├hasBrushExist ┤                            └nothing,┘        ├visualByRecord.\n         *                └!hasBrushExist┘                                              └nothing.\n         * ( !brushed  && ┬hasBrushExist ┬ && linkOthers  ) => StepA:  nothing,  StepB: ┬visualByRecord.\n         *                └!hasBrushExist┘                                              └nothing.\n         * ( brushed ┬ &&                     !linkOthers ) => StepA:  nothing,  StepB: ┬visualByCheck.\n         *   !brushed┘                                                                  └nothing.\n         * ( !brushed  &&                     !linkOthers ) => StepA:  nothing,  StepB:  nothing.\n         */\n\n        // Step A\n        ecModel.eachSeries(function (seriesModel, seriesIndex) {\n            var rangeInfoList = rangeInfoBySeries[seriesIndex] = [];\n\n            seriesModel.subType === 'parallel'\n                ? stepAParallel(seriesModel, seriesIndex, rangeInfoList)\n                : stepAOthers(seriesModel, seriesIndex, rangeInfoList);\n        });\n\n        function stepAParallel(seriesModel, seriesIndex) {\n            var coordSys = seriesModel.coordinateSystem;\n            hasBrushExists |= coordSys.hasAxisBrushed();\n\n            linkOthers(seriesIndex) && coordSys.eachActiveState(\n                seriesModel.getData(),\n                function (activeState, dataIndex) {\n                    activeState === 'active' && (selectedDataIndexForLink[dataIndex] = 1);\n                }\n            );\n        }\n\n        function stepAOthers(seriesModel, seriesIndex, rangeInfoList) {\n            var selectorsByBrushType = getSelectorsByBrushType(seriesModel);\n            if (!selectorsByBrushType || brushModelNotControll(brushModel, seriesIndex)) {\n                return;\n            }\n\n            each$1(areas, function (area) {\n                selectorsByBrushType[area.brushType]\n                    && brushModel.brushTargetManager.controlSeries(area, seriesModel, ecModel)\n                    && rangeInfoList.push(area);\n                hasBrushExists |= brushed(rangeInfoList);\n            });\n\n            if (linkOthers(seriesIndex) && brushed(rangeInfoList)) {\n                var data = seriesModel.getData();\n                data.each(function (dataIndex) {\n                    if (checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)) {\n                        selectedDataIndexForLink[dataIndex] = 1;\n                    }\n                });\n            }\n        }\n\n        // Step B\n        ecModel.eachSeries(function (seriesModel, seriesIndex) {\n            var seriesBrushSelected = {\n                seriesId: seriesModel.id,\n                seriesIndex: seriesIndex,\n                seriesName: seriesModel.name,\n                dataIndex: []\n            };\n            // Every series exists in event params, convenient\n            // for user to find series by seriesIndex.\n            thisBrushSelected.selected.push(seriesBrushSelected);\n\n            var selectorsByBrushType = getSelectorsByBrushType(seriesModel);\n            var rangeInfoList = rangeInfoBySeries[seriesIndex];\n\n            var data = seriesModel.getData();\n            var getValueState = linkOthers(seriesIndex)\n                ? function (dataIndex) {\n                    return selectedDataIndexForLink[dataIndex]\n                        ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush')\n                        : 'outOfBrush';\n                }\n                : function (dataIndex) {\n                    return checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)\n                        ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush')\n                        : 'outOfBrush';\n                };\n\n            // If no supported brush or no brush, all visuals are in original state.\n            (linkOthers(seriesIndex) ? hasBrushExists : brushed(rangeInfoList))\n                && applyVisual(\n                    STATE_LIST, visualMappings, data, getValueState\n                );\n        });\n\n    });\n\n    dispatchAction(api, throttleType, throttleDelay, brushSelected, payload);\n});\n\nfunction dispatchAction(api, throttleType, throttleDelay, brushSelected, payload) {\n    // This event will not be triggered when `setOpion`, otherwise dead lock may\n    // triggered when do `setOption` in event listener, which we do not find\n    // satisfactory way to solve yet. Some considered resolutions:\n    // (a) Diff with prevoius selected data ant only trigger event when changed.\n    // But store previous data and diff precisely (i.e., not only by dataIndex, but\n    // also detect value changes in selected data) might bring complexity or fragility.\n    // (b) Use spectial param like `silent` to suppress event triggering.\n    // But such kind of volatile param may be weird in `setOption`.\n    if (!payload) {\n        return;\n    }\n\n    var zr = api.getZr();\n    if (zr[DISPATCH_FLAG]) {\n        return;\n    }\n\n    if (!zr[DISPATCH_METHOD]) {\n        zr[DISPATCH_METHOD] = doDispatch;\n    }\n\n    var fn = createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType);\n\n    fn(api, brushSelected);\n}\n\nfunction doDispatch(api, brushSelected) {\n    if (!api.isDisposed()) {\n        var zr = api.getZr();\n        zr[DISPATCH_FLAG] = true;\n        api.dispatchAction({\n            type: 'brushSelect',\n            batch: brushSelected\n        });\n        zr[DISPATCH_FLAG] = false;\n    }\n}\n\nfunction checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex) {\n    for (var i = 0, len = rangeInfoList.length; i < len; i++) {\n        var area = rangeInfoList[i];\n        if (selectorsByBrushType[area.brushType](\n            dataIndex, data, area.selectors, area\n        )) {\n            return true;\n        }\n    }\n}\n\nfunction getSelectorsByBrushType(seriesModel) {\n    var brushSelector = seriesModel.brushSelector;\n    if (isString(brushSelector)) {\n        var sels = [];\n        each$1(selector, function (selectorsByElementType, brushType) {\n            sels[brushType] = function (dataIndex, data, selectors, area) {\n                var itemLayout = data.getItemLayout(dataIndex);\n                return selectorsByElementType[brushSelector](itemLayout, selectors, area);\n            };\n        });\n        return sels;\n    }\n    else if (isFunction$1(brushSelector)) {\n        var bSelector = {};\n        each$1(selector, function (sel, brushType) {\n            bSelector[brushType] = brushSelector;\n        });\n        return bSelector;\n    }\n    return brushSelector;\n}\n\nfunction brushModelNotControll(brushModel, seriesIndex) {\n    var seriesIndices = brushModel.option.seriesIndex;\n    return seriesIndices != null\n        && seriesIndices !== 'all'\n        && (\n            isArray(seriesIndices)\n            ? indexOf(seriesIndices, seriesIndex) < 0\n            : seriesIndex !== seriesIndices\n        );\n}\n\nfunction bindSelector(area) {\n    var selectors = area.selectors = {};\n    each$1(selector[area.brushType], function (selFn, elType) {\n        // Do not use function binding or curry for performance.\n        selectors[elType] = function (itemLayout) {\n            return selFn(itemLayout, selectors, area);\n        };\n    });\n    return area;\n}\n\nvar boundingRectBuilders = {\n\n    lineX: noop,\n\n    lineY: noop,\n\n    rect: function (area) {\n        return getBoundingRectFromMinMax(area.range);\n    },\n\n    polygon: function (area) {\n        var minMax;\n        var range = area.range;\n\n        for (var i = 0, len = range.length; i < len; i++) {\n            minMax = minMax || [[Infinity, -Infinity], [Infinity, -Infinity]];\n            var rg = range[i];\n            rg[0] < minMax[0][0] && (minMax[0][0] = rg[0]);\n            rg[0] > minMax[0][1] && (minMax[0][1] = rg[0]);\n            rg[1] < minMax[1][0] && (minMax[1][0] = rg[1]);\n            rg[1] > minMax[1][1] && (minMax[1][1] = rg[1]);\n        }\n\n        return minMax && getBoundingRectFromMinMax(minMax);\n    }\n};\n\nfunction getBoundingRectFromMinMax(minMax) {\n    return new BoundingRect(\n        minMax[0][0],\n        minMax[1][0],\n        minMax[0][1] - minMax[0][0],\n        minMax[1][1] - minMax[1][0]\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_OUT_OF_BRUSH_COLOR = ['#ddd'];\n\nvar BrushModel = extendComponentModel({\n\n    type: 'brush',\n\n    dependencies: ['geo', 'grid', 'xAxis', 'yAxis', 'parallel', 'series'],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        // inBrush: null,\n        // outOfBrush: null,\n        toolbox: null,          // Default value see preprocessor.\n        brushLink: null,        // Series indices array, broadcast using dataIndex.\n                                // or 'all', which means all series. 'none' or null means no series.\n        seriesIndex: 'all',     // seriesIndex array, specify series controlled by this brush component.\n        geoIndex: null,         //\n        xAxisIndex: null,\n        yAxisIndex: null,\n\n        brushType: 'rect',      // Default brushType, see BrushController.\n        brushMode: 'single',    // Default brushMode, 'single' or 'multiple'\n        transformable: true,    // Default transformable.\n        brushStyle: {           // Default brushStyle\n            borderWidth: 1,\n            color: 'rgba(120,140,180,0.3)',\n            borderColor: 'rgba(120,140,180,0.8)'\n        },\n\n        throttleType: 'fixRate', // Throttle in brushSelected event. 'fixRate' or 'debounce'.\n                                 // If null, no throttle. Valid only in the first brush component\n        throttleDelay: 0,        // Unit: ms, 0 means every event will be triggered.\n\n        // FIXME\n        // 试验效果\n        removeOnClick: true,\n\n        z: 10000\n    },\n\n    /**\n     * @readOnly\n     * @type {Array.<Object>}\n     */\n    areas: [],\n\n    /**\n     * Current activated brush type.\n     * If null, brush is inactived.\n     * see module:echarts/component/helper/BrushController\n     * @readOnly\n     * @type {string}\n     */\n    brushType: null,\n\n    /**\n     * Current brush opt.\n     * see module:echarts/component/helper/BrushController\n     * @readOnly\n     * @type {Object}\n     */\n    brushOption: {},\n\n    /**\n     * @readOnly\n     * @type {Array.<Object>}\n     */\n    coordInfoList: [],\n\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n\n        !isInit && replaceVisualOption(\n            thisOption, newOption, ['inBrush', 'outOfBrush']\n        );\n\n        var inBrush = thisOption.inBrush = thisOption.inBrush || {};\n        // Always give default visual, consider setOption at the second time.\n        thisOption.outOfBrush = thisOption.outOfBrush || {color: DEFAULT_OUT_OF_BRUSH_COLOR};\n\n        if (!inBrush.hasOwnProperty('liftZ')) {\n            // Bigger than the highlight z lift, otherwise it will\n            // be effected by the highlight z when brush.\n            inBrush.liftZ = 5;\n        }\n    },\n\n    /**\n     * If ranges is null/undefined, range state remain.\n     *\n     * @param {Array.<Object>} [ranges]\n     */\n    setAreas: function (areas) {\n        if (__DEV__) {\n            assert$1(isArray(areas));\n            each$1(areas, function (area) {\n                assert$1(area.brushType, 'Illegal areas');\n            });\n        }\n\n        // If ranges is null/undefined, range state remain.\n        // This helps user to dispatchAction({type: 'brush'}) with no areas\n        // set but just want to get the current brush select info from a `brush` event.\n        if (!areas) {\n            return;\n        }\n\n        this.areas = map(areas, function (area) {\n            return generateBrushOption(this.option, area);\n        }, this);\n    },\n\n    /**\n     * see module:echarts/component/helper/BrushController\n     * @param {Object} brushOption\n     */\n    setBrushOption: function (brushOption) {\n        this.brushOption = generateBrushOption(this.option, brushOption);\n        this.brushType = this.brushOption.brushType;\n    }\n\n});\n\nfunction generateBrushOption(option, brushOption) {\n    return merge(\n        {\n            brushType: option.brushType,\n            brushMode: option.brushMode,\n            transformable: option.transformable,\n            brushStyle: new Model(option.brushStyle).getItemStyle(),\n            removeOnClick: option.removeOnClick,\n            z: option.z\n        },\n        brushOption,\n        true\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'brush',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @readOnly\n         * @type {module:echarts/model/Global}\n         */\n        this.ecModel = ecModel;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this.api = api;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/component/brush/BrushModel}\n         */\n        this.model;\n\n        /**\n         * @private\n         * @type {module:echarts/component/helper/BrushController}\n         */\n        (this._brushController = new BrushController(api.getZr()))\n            .on('brush', bind(this._onBrush, this))\n            .mount();\n    },\n\n    /**\n     * @override\n     */\n    render: function (brushModel) {\n        this.model = brushModel;\n        return updateController.apply(this, arguments);\n    },\n\n    /**\n     * @override\n     */\n    updateTransform: updateController,\n\n    /**\n     * @override\n     */\n    updateView: updateController,\n\n    // /**\n    //  * @override\n    //  */\n    // updateLayout: updateController,\n\n    // /**\n    //  * @override\n    //  */\n    // updateVisual: updateController,\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._brushController.dispose();\n    },\n\n    /**\n     * @private\n     */\n    _onBrush: function (areas, opt) {\n        var modelId = this.model.id;\n\n        this.model.brushTargetManager.setOutputRanges(areas, this.ecModel);\n\n        // Action is not dispatched on drag end, because the drag end\n        // emits the same params with the last drag move event, and\n        // may have some delay when using touch pad, which makes\n        // animation not smooth (when using debounce).\n        (!opt.isEnd || opt.removeOnClick) && this.api.dispatchAction({\n            type: 'brush',\n            brushId: modelId,\n            areas: clone(areas),\n            $from: modelId\n        });\n    }\n\n});\n\nfunction updateController(brushModel, ecModel, api, payload) {\n    // Do not update controller when drawing.\n    (!payload || payload.$from !== brushModel.id) && this._brushController\n        .setPanels(brushModel.brushTargetManager.makePanelOpts(api))\n        .enableBrush(brushModel.brushOption)\n        .updateCovers(brushModel.areas.slice());\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * payload: {\n *      brushIndex: number, or,\n *      brushId: string, or,\n *      brushName: string,\n *      globalRanges: Array\n * }\n */\nregisterAction(\n        {type: 'brush', event: 'brush' /*, update: 'updateView' */},\n    function (payload, ecModel) {\n        ecModel.eachComponent({mainType: 'brush', query: payload}, function (brushModel) {\n            brushModel.setAreas(payload.areas);\n        });\n    }\n);\n\n/**\n * payload: {\n *      brushComponents: [\n *          {\n *              brushId,\n *              brushIndex,\n *              brushName,\n *              series: [\n *                  {\n *                      seriesId,\n *                      seriesIndex,\n *                      seriesName,\n *                      rawIndices: [21, 34, ...]\n *                  },\n *                  ...\n *              ]\n *          },\n *          ...\n *      ]\n * }\n */\nregisterAction(\n    {type: 'brushSelect', event: 'brushSelected', update: 'none'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar features = {};\n\nfunction register$1(name, ctor) {\n    features[name] = ctor;\n}\n\nfunction get$1(name) {\n    return features[name];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar brushLang = lang.toolbox.brush;\n\nfunction Brush(model, ecModel, api) {\n    this.model = model;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._brushMode;\n}\n\nBrush.defaultOption = {\n    show: true,\n    type: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'],\n    icon: {\n        /* eslint-disable */\n        rect: 'M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13', // jshint ignore:line\n        polygon: 'M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2', // jshint ignore:line\n        lineX: 'M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4', // jshint ignore:line\n        lineY: 'M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4', // jshint ignore:line\n        keep: 'M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z', // jshint ignore:line\n        clear: 'M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2' // jshint ignore:line\n        /* eslint-enable */\n    },\n    // `rect`, `polygon`, `lineX`, `lineY`, `keep`, `clear`\n    title: clone(brushLang.title)\n};\n\nvar proto$3 = Brush.prototype;\n\n// proto.updateLayout = function (featureModel, ecModel, api) {\n/* eslint-disable */\nproto$3.render =\n/* eslint-enable */\nproto$3.updateView = function (featureModel, ecModel, api) {\n    var brushType;\n    var brushMode;\n    var isBrushed;\n\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel) {\n        brushType = brushModel.brushType;\n        brushMode = brushModel.brushOption.brushMode || 'single';\n        isBrushed |= brushModel.areas.length;\n    });\n    this._brushType = brushType;\n    this._brushMode = brushMode;\n\n    each$1(featureModel.get('type', true), function (type) {\n        featureModel.setIconStatus(\n            type,\n            (\n                type === 'keep'\n                ? brushMode === 'multiple'\n                : type === 'clear'\n                ? isBrushed\n                : type === brushType\n            ) ? 'emphasis' : 'normal'\n        );\n    });\n};\n\nproto$3.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon', true);\n    var icons = {};\n    each$1(model.get('type', true), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nproto$3.onclick = function (ecModel, api, type) {\n    var brushType = this._brushType;\n    var brushMode = this._brushMode;\n\n    if (type === 'clear') {\n        // Trigger parallel action firstly\n        api.dispatchAction({\n            type: 'axisAreaSelect',\n            intervals: []\n        });\n\n        api.dispatchAction({\n            type: 'brush',\n            command: 'clear',\n            // Clear all areas of all brush components.\n            areas: []\n        });\n    }\n    else {\n        api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'brush',\n            brushOption: {\n                brushType: type === 'keep'\n                    ? brushType\n                    : (brushType === type ? false : type),\n                brushMode: type === 'keep'\n                    ? (brushMode === 'multiple' ? 'single' : 'multiple')\n                    : brushMode\n            }\n        });\n    }\n};\n\nregister$1('brush', Brush);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Brush component entry\n */\n\nregisterPreprocessor(preprocessor$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (24*60*60*1000)\nvar PROXIMATE_ONE_DAY = 86400000;\n\n/**\n * Calendar\n *\n * @constructor\n *\n * @param {Object} calendarModel calendarModel\n * @param {Object} ecModel       ecModel\n * @param {Object} api           api\n */\nfunction Calendar(calendarModel, ecModel, api) {\n    this._model = calendarModel;\n}\n\nCalendar.prototype = {\n\n    constructor: Calendar,\n\n    type: 'calendar',\n\n    dimensions: ['time', 'value'],\n\n    // Required in createListFromData\n    getDimensionsInfo: function () {\n        return [{name: 'time', type: 'time'}, 'value'];\n    },\n\n    getRangeInfo: function () {\n        return this._rangeInfo;\n    },\n\n    getModel: function () {\n        return this._model;\n    },\n\n    getRect: function () {\n        return this._rect;\n    },\n\n    getCellWidth: function () {\n        return this._sw;\n    },\n\n    getCellHeight: function () {\n        return this._sh;\n    },\n\n    getOrient: function () {\n        return this._orient;\n    },\n\n    /**\n     * getFirstDayOfWeek\n     *\n     * @example\n     *     0 : start at Sunday\n     *     1 : start at Monday\n     *\n     * @return {number}\n     */\n    getFirstDayOfWeek: function () {\n        return this._firstDayOfWeek;\n    },\n\n    /**\n     * get date info\n     *\n     * @param  {string|number} date date\n     * @return {Object}\n     * {\n     *      y: string, local full year, eg., '1940',\n     *      m: string, local month, from '01' ot '12',\n     *      d: string, local date, from '01' to '31' (if exists),\n     *      day: It is not date.getDay(). It is the location of the cell in a week, from 0 to 6,\n     *      time: timestamp,\n     *      formatedDate: string, yyyy-MM-dd,\n     *      date: original date object.\n     * }\n     */\n    getDateInfo: function (date) {\n\n        date = parseDate(date);\n\n        var y = date.getFullYear();\n\n        var m = date.getMonth() + 1;\n        m = m < 10 ? '0' + m : m;\n\n        var d = date.getDate();\n        d = d < 10 ? '0' + d : d;\n\n        var day = date.getDay();\n\n        day = Math.abs((day + 7 - this.getFirstDayOfWeek()) % 7);\n\n        return {\n            y: y,\n            m: m,\n            d: d,\n            day: day,\n            time: date.getTime(),\n            formatedDate: y + '-' + m + '-' + d,\n            date: date\n        };\n    },\n\n    getNextNDay: function (date, n) {\n        n = n || 0;\n        if (n === 0) {\n            return this.getDateInfo(date);\n        }\n\n        date = new Date(this.getDateInfo(date).time);\n        date.setDate(date.getDate() + n);\n\n        return this.getDateInfo(date);\n    },\n\n    update: function (ecModel, api) {\n\n        this._firstDayOfWeek = +this._model.getModel('dayLabel').get('firstDay');\n        this._orient = this._model.get('orient');\n        this._lineWidth = this._model.getModel('itemStyle').getItemStyle().lineWidth || 0;\n\n\n        this._rangeInfo = this._getRangeInfo(this._initRangeOption());\n        var weeks = this._rangeInfo.weeks || 1;\n        var whNames = ['width', 'height'];\n        var cellSize = this._model.get('cellSize').slice();\n        var layoutParams = this._model.getBoxLayoutParams();\n        var cellNumbers = this._orient === 'horizontal' ? [weeks, 7] : [7, weeks];\n\n        each$1([0, 1], function (idx) {\n            if (cellSizeSpecified(cellSize, idx)) {\n                layoutParams[whNames[idx]] = cellSize[idx] * cellNumbers[idx];\n            }\n        });\n\n        var whGlobal = {\n            width: api.getWidth(),\n            height: api.getHeight()\n        };\n        var calendarRect = this._rect = getLayoutRect(layoutParams, whGlobal);\n\n        each$1([0, 1], function (idx) {\n            if (!cellSizeSpecified(cellSize, idx)) {\n                cellSize[idx] = calendarRect[whNames[idx]] / cellNumbers[idx];\n            }\n        });\n\n        function cellSizeSpecified(cellSize, idx) {\n            return cellSize[idx] != null && cellSize[idx] !== 'auto';\n        }\n\n        this._sw = cellSize[0];\n        this._sh = cellSize[1];\n    },\n\n\n    /**\n     * Convert a time data(time, value) item to (x, y) point.\n     *\n     * @override\n     * @param  {Array|number} data data\n     * @param  {boolean} [clamp=true] out of range\n     * @return {Array} point\n     */\n    dataToPoint: function (data, clamp) {\n        isArray(data) && (data = data[0]);\n        clamp == null && (clamp = true);\n\n        var dayInfo = this.getDateInfo(data);\n        var range = this._rangeInfo;\n        var date = dayInfo.formatedDate;\n\n        // if not in range return [NaN, NaN]\n        if (clamp && !(\n            dayInfo.time >= range.start.time\n            && dayInfo.time < range.end.time + PROXIMATE_ONE_DAY\n        )) {\n            return [NaN, NaN];\n        }\n\n        var week = dayInfo.day;\n        var nthWeek = this._getRangeInfo([range.start.time, date]).nthWeek;\n\n        if (this._orient === 'vertical') {\n            return [\n                this._rect.x + week * this._sw + this._sw / 2,\n                this._rect.y + nthWeek * this._sh + this._sh / 2\n            ];\n\n        }\n\n        return [\n            this._rect.x + nthWeek * this._sw + this._sw / 2,\n            this._rect.y + week * this._sh + this._sh / 2\n        ];\n\n    },\n\n    /**\n     * Convert a (x, y) point to time data\n     *\n     * @override\n     * @param  {string} point point\n     * @return {string}       data\n     */\n    pointToData: function (point) {\n\n        var date = this.pointToDate(point);\n\n        return date && date.time;\n    },\n\n    /**\n     * Convert a time date item to (x, y) four point.\n     *\n     * @param  {Array} data  date[0] is date\n     * @param  {boolean} [clamp=true]  out of range\n     * @return {Object}       point\n     */\n    dataToRect: function (data, clamp) {\n        var point = this.dataToPoint(data, clamp);\n\n        return {\n            contentShape: {\n                x: point[0] - (this._sw - this._lineWidth) / 2,\n                y: point[1] - (this._sh - this._lineWidth) / 2,\n                width: this._sw - this._lineWidth,\n                height: this._sh - this._lineWidth\n            },\n\n            center: point,\n\n            tl: [\n                point[0] - this._sw / 2,\n                point[1] - this._sh / 2\n            ],\n\n            tr: [\n                point[0] + this._sw / 2,\n                point[1] - this._sh / 2\n            ],\n\n            br: [\n                point[0] + this._sw / 2,\n                point[1] + this._sh / 2\n            ],\n\n            bl: [\n                point[0] - this._sw / 2,\n                point[1] + this._sh / 2\n            ]\n\n        };\n    },\n\n    /**\n     * Convert a (x, y) point to time date\n     *\n     * @param  {Array} point point\n     * @return {Object}       date\n     */\n    pointToDate: function (point) {\n        var nthX = Math.floor((point[0] - this._rect.x) / this._sw) + 1;\n        var nthY = Math.floor((point[1] - this._rect.y) / this._sh) + 1;\n        var range = this._rangeInfo.range;\n\n        if (this._orient === 'vertical') {\n            return this._getDateByWeeksAndDay(nthY, nthX - 1, range);\n        }\n\n        return this._getDateByWeeksAndDay(nthX, nthY - 1, range);\n    },\n\n    /**\n     * @inheritDoc\n     */\n    convertToPixel: curry(doConvert$2, 'dataToPoint'),\n\n    /**\n     * @inheritDoc\n     */\n    convertFromPixel: curry(doConvert$2, 'pointToData'),\n\n    /**\n     * initRange\n     *\n     * @private\n     * @return {Array} [start, end]\n     */\n    _initRangeOption: function () {\n        var range = this._model.get('range');\n\n        var rg = range;\n\n        if (isArray(rg) && rg.length === 1) {\n            rg = rg[0];\n        }\n\n        if (/^\\d{4}$/.test(rg)) {\n            range = [rg + '-01-01', rg + '-12-31'];\n        }\n\n        if (/^\\d{4}[\\/|-]\\d{1,2}$/.test(rg)) {\n\n            var start = this.getDateInfo(rg);\n            var firstDay = start.date;\n            firstDay.setMonth(firstDay.getMonth() + 1);\n\n            var end = this.getNextNDay(firstDay, -1);\n            range = [start.formatedDate, end.formatedDate];\n        }\n\n        if (/^\\d{4}[\\/|-]\\d{1,2}[\\/|-]\\d{1,2}$/.test(rg)) {\n            range = [rg, rg];\n        }\n\n        var tmp = this._getRangeInfo(range);\n\n        if (tmp.start.time > tmp.end.time) {\n            range.reverse();\n        }\n\n        return range;\n    },\n\n    /**\n     * range info\n     *\n     * @private\n     * @param  {Array} range range ['2017-01-01', '2017-07-08']\n     *  If range[0] > range[1], they will not be reversed.\n     * @return {Object}       obj\n     */\n    _getRangeInfo: function (range) {\n        range = [\n            this.getDateInfo(range[0]),\n            this.getDateInfo(range[1])\n        ];\n\n        var reversed;\n        if (range[0].time > range[1].time) {\n            reversed = true;\n            range.reverse();\n        }\n\n        var allDay = Math.floor(range[1].time / PROXIMATE_ONE_DAY)\n            - Math.floor(range[0].time / PROXIMATE_ONE_DAY) + 1;\n\n        // Consider case:\n        // Firstly set system timezone as \"Time Zone: America/Toronto\",\n        // ```\n        // var first = new Date(1478412000000 - 3600 * 1000 * 2.5);\n        // var second = new Date(1478412000000);\n        // var allDays = Math.floor(second / ONE_DAY) - Math.floor(first / ONE_DAY) + 1;\n        // ```\n        // will get wrong result because of DST. So we should fix it.\n        var date = new Date(range[0].time);\n        var startDateNum = date.getDate();\n        var endDateNum = range[1].date.getDate();\n        date.setDate(startDateNum + allDay - 1);\n        // The bias can not over a month, so just compare date.\n        if (date.getDate() !== endDateNum) {\n            var sign = date.getTime() - range[1].time > 0 ? 1 : -1;\n            while (date.getDate() !== endDateNum && (date.getTime() - range[1].time) * sign > 0) {\n                allDay -= sign;\n                date.setDate(startDateNum + allDay - 1);\n            }\n        }\n\n        var weeks = Math.floor((allDay + range[0].day + 6) / 7);\n        var nthWeek = reversed ? -weeks + 1 : weeks - 1;\n\n        reversed && range.reverse();\n\n        return {\n            range: [range[0].formatedDate, range[1].formatedDate],\n            start: range[0],\n            end: range[1],\n            allDay: allDay,\n            weeks: weeks,\n            // From 0.\n            nthWeek: nthWeek,\n            fweek: range[0].day,\n            lweek: range[1].day\n        };\n    },\n\n    /**\n     * get date by nthWeeks and week day in range\n     *\n     * @private\n     * @param  {number} nthWeek the week\n     * @param  {number} day   the week day\n     * @param  {Array} range [d1, d2]\n     * @return {Object}\n     */\n    _getDateByWeeksAndDay: function (nthWeek, day, range) {\n        var rangeInfo = this._getRangeInfo(range);\n\n        if (nthWeek > rangeInfo.weeks\n            || (nthWeek === 0 && day < rangeInfo.fweek)\n            || (nthWeek === rangeInfo.weeks && day > rangeInfo.lweek)\n        ) {\n            return false;\n        }\n\n        var nthDay = (nthWeek - 1) * 7 - rangeInfo.fweek + day;\n        var date = new Date(rangeInfo.start.time);\n        date.setDate(rangeInfo.start.d + nthDay);\n\n        return this.getDateInfo(date);\n    }\n};\n\nCalendar.dimensions = Calendar.prototype.dimensions;\n\nCalendar.getDimensionsInfo = Calendar.prototype.getDimensionsInfo;\n\nCalendar.create = function (ecModel, api) {\n    var calendarList = [];\n\n    ecModel.eachComponent('calendar', function (calendarModel) {\n        var calendar = new Calendar(calendarModel, ecModel, api);\n        calendarList.push(calendar);\n        calendarModel.coordinateSystem = calendar;\n    });\n\n    ecModel.eachSeries(function (calendarSeries) {\n        if (calendarSeries.get('coordinateSystem') === 'calendar') {\n            // Inject coordinate system\n            calendarSeries.coordinateSystem = calendarList[calendarSeries.get('calendarIndex') || 0];\n        }\n    });\n    return calendarList;\n};\n\nfunction doConvert$2(methodName, ecModel, finder, value) {\n    var calendarModel = finder.calendarModel;\n    var seriesModel = finder.seriesModel;\n\n    var coordSys = calendarModel\n        ? calendarModel.coordinateSystem\n        : seriesModel\n        ? seriesModel.coordinateSystem\n        : null;\n\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\nCoordinateSystemManager.register('calendar', Calendar);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CalendarModel = ComponentModel.extend({\n\n    type: 'calendar',\n\n    /**\n     * @type {module:echarts/coord/calendar/Calendar}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        left: 80,\n        top: 60,\n\n        cellSize: 20,\n\n        // horizontal vertical\n        orient: 'horizontal',\n\n        // month separate line style\n        splitLine: {\n            show: true,\n            lineStyle: {\n                color: '#000',\n                width: 1,\n                type: 'solid'\n            }\n        },\n\n        // rect style  temporarily unused emphasis\n        itemStyle: {\n            color: '#fff',\n            borderWidth: 1,\n            borderColor: '#ccc'\n        },\n\n        // week text style\n        dayLabel: {\n            show: true,\n\n            // a week first day\n            firstDay: 0,\n\n            // start end\n            position: 'start',\n            margin: '50%', // 50% of cellSize\n            nameMap: 'en',\n            color: '#000'\n        },\n\n        // month text style\n        monthLabel: {\n            show: true,\n\n            // start end\n            position: 'start',\n            margin: 5,\n\n            // center or left\n            align: 'center',\n\n            // cn en []\n            nameMap: 'en',\n            formatter: null,\n            color: '#000'\n        },\n\n        // year text style\n        yearLabel: {\n            show: true,\n\n            // top bottom left right\n            position: null,\n            margin: 30,\n            formatter: null,\n            color: '#ccc',\n            fontFamily: 'sans-serif',\n            fontWeight: 'bolder',\n            fontSize: 20\n        }\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        CalendarModel.superApply(this, 'init', arguments);\n\n        mergeAndNormalizeLayoutParams$1(option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        CalendarModel.superApply(this, 'mergeOption', arguments);\n\n        mergeAndNormalizeLayoutParams$1(this.option, option);\n    }\n});\n\nfunction mergeAndNormalizeLayoutParams$1(target, raw) {\n    // Normalize cellSize\n    var cellSize = target.cellSize;\n\n    if (!isArray(cellSize)) {\n        cellSize = target.cellSize = [cellSize, cellSize];\n    }\n    else if (cellSize.length === 1) {\n        cellSize[1] = cellSize[0];\n    }\n\n    var ignoreSize = map([0, 1], function (hvIdx) {\n        // If user have set `width` or both `left` and `right`, cellSize\n        // will be automatically set to 'auto', otherwise the default\n        // setting of cellSize will make `width` setting not work.\n        if (sizeCalculable(raw, hvIdx)) {\n            cellSize[hvIdx] = 'auto';\n        }\n        return cellSize[hvIdx] != null && cellSize[hvIdx] !== 'auto';\n    });\n\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MONTH_TEXT = {\n    EN: [\n        'Jan', 'Feb', 'Mar',\n        'Apr', 'May', 'Jun',\n        'Jul', 'Aug', 'Sep',\n        'Oct', 'Nov', 'Dec'\n    ],\n    CN: [\n        '一月', '二月', '三月',\n        '四月', '五月', '六月',\n        '七月', '八月', '九月',\n        '十月', '十一月', '十二月'\n    ]\n};\n\nvar WEEK_TEXT = {\n    EN: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],\n    CN: ['日', '一', '二', '三', '四', '五', '六']\n};\n\nextendComponentView({\n\n    type: 'calendar',\n\n    /**\n     * top/left line points\n     *  @private\n     */\n    _tlpoints: null,\n\n    /**\n     * bottom/right line points\n     *  @private\n     */\n    _blpoints: null,\n\n    /**\n     * first day of month\n     *  @private\n     */\n    _firstDayOfMonth: null,\n\n    /**\n     * first day point of month\n     *  @private\n     */\n    _firstDayPoints: null,\n\n    render: function (calendarModel, ecModel, api) {\n\n        var group = this.group;\n\n        group.removeAll();\n\n        var coordSys = calendarModel.coordinateSystem;\n\n        // range info\n        var rangeData = coordSys.getRangeInfo();\n        var orient = coordSys.getOrient();\n\n        this._renderDayRect(calendarModel, rangeData, group);\n\n        // _renderLines must be called prior to following function\n        this._renderLines(calendarModel, rangeData, orient, group);\n\n        this._renderYearText(calendarModel, rangeData, orient, group);\n\n        this._renderMonthText(calendarModel, orient, group);\n\n        this._renderWeekText(calendarModel, rangeData, orient, group);\n    },\n\n    // render day rect\n    _renderDayRect: function (calendarModel, rangeData, group) {\n        var coordSys = calendarModel.coordinateSystem;\n        var itemRectStyleModel = calendarModel.getModel('itemStyle').getItemStyle();\n        var sw = coordSys.getCellWidth();\n        var sh = coordSys.getCellHeight();\n\n        for (var i = rangeData.start.time;\n            i <= rangeData.end.time;\n            i = coordSys.getNextNDay(i, 1).time\n        ) {\n\n            var point = coordSys.dataToRect([i], false).tl;\n\n            // every rect\n            var rect = new Rect({\n                shape: {\n                    x: point[0],\n                    y: point[1],\n                    width: sw,\n                    height: sh\n                },\n                cursor: 'default',\n                style: itemRectStyleModel\n            });\n\n            group.add(rect);\n        }\n\n    },\n\n    // render separate line\n    _renderLines: function (calendarModel, rangeData, orient, group) {\n\n        var self = this;\n\n        var coordSys = calendarModel.coordinateSystem;\n\n        var lineStyleModel = calendarModel.getModel('splitLine.lineStyle').getLineStyle();\n        var show = calendarModel.get('splitLine.show');\n\n        var lineWidth = lineStyleModel.lineWidth;\n\n        this._tlpoints = [];\n        this._blpoints = [];\n        this._firstDayOfMonth = [];\n        this._firstDayPoints = [];\n\n\n        var firstDay = rangeData.start;\n\n        for (var i = 0; firstDay.time <= rangeData.end.time; i++) {\n            addPoints(firstDay.formatedDate);\n\n            if (i === 0) {\n                firstDay = coordSys.getDateInfo(rangeData.start.y + '-' + rangeData.start.m);\n            }\n\n            var date = firstDay.date;\n            date.setMonth(date.getMonth() + 1);\n            firstDay = coordSys.getDateInfo(date);\n        }\n\n        addPoints(coordSys.getNextNDay(rangeData.end.time, 1).formatedDate);\n\n        function addPoints(date) {\n\n            self._firstDayOfMonth.push(coordSys.getDateInfo(date));\n            self._firstDayPoints.push(coordSys.dataToRect([date], false).tl);\n\n            var points = self._getLinePointsOfOneWeek(calendarModel, date, orient);\n\n            self._tlpoints.push(points[0]);\n            self._blpoints.push(points[points.length - 1]);\n\n            show && self._drawSplitline(points, lineStyleModel, group);\n        }\n\n\n        // render top/left line\n        show && this._drawSplitline(self._getEdgesPoints(self._tlpoints, lineWidth, orient), lineStyleModel, group);\n\n        // render bottom/right line\n        show && this._drawSplitline(self._getEdgesPoints(self._blpoints, lineWidth, orient), lineStyleModel, group);\n\n    },\n\n    // get points at both ends\n    _getEdgesPoints: function (points, lineWidth, orient) {\n        var rs = [points[0].slice(), points[points.length - 1].slice()];\n        var idx = orient === 'horizontal' ? 0 : 1;\n\n        // both ends of the line are extend half lineWidth\n        rs[0][idx] = rs[0][idx] - lineWidth / 2;\n        rs[1][idx] = rs[1][idx] + lineWidth / 2;\n\n        return rs;\n    },\n\n    // render split line\n    _drawSplitline: function (points, lineStyleModel, group) {\n\n        var poyline = new Polyline({\n            z2: 20,\n            shape: {\n                points: points\n            },\n            style: lineStyleModel\n        });\n\n        group.add(poyline);\n    },\n\n    // render month line of one week points\n    _getLinePointsOfOneWeek: function (calendarModel, date, orient) {\n\n        var coordSys = calendarModel.coordinateSystem;\n        date = coordSys.getDateInfo(date);\n\n        var points = [];\n\n        for (var i = 0; i < 7; i++) {\n\n            var tmpD = coordSys.getNextNDay(date.time, i);\n            var point = coordSys.dataToRect([tmpD.time], false);\n\n            points[2 * tmpD.day] = point.tl;\n            points[2 * tmpD.day + 1] = point[orient === 'horizontal' ? 'bl' : 'tr'];\n        }\n\n        return points;\n\n    },\n\n    _formatterLabel: function (formatter, params) {\n\n        if (typeof formatter === 'string' && formatter) {\n            return formatTplSimple(formatter, params);\n        }\n\n        if (typeof formatter === 'function') {\n            return formatter(params);\n        }\n\n        return params.nameMap;\n\n    },\n\n    _yearTextPositionControl: function (textEl, point, orient, position, margin) {\n\n        point = point.slice();\n        var aligns = ['center', 'bottom'];\n\n        if (position === 'bottom') {\n            point[1] += margin;\n            aligns = ['center', 'top'];\n        }\n        else if (position === 'left') {\n            point[0] -= margin;\n        }\n        else if (position === 'right') {\n            point[0] += margin;\n            aligns = ['center', 'top'];\n        }\n        else { // top\n            point[1] -= margin;\n        }\n\n        var rotate = 0;\n        if (position === 'left' || position === 'right') {\n            rotate = Math.PI / 2;\n        }\n\n        return {\n            rotation: rotate,\n            position: point,\n            style: {\n                textAlign: aligns[0],\n                textVerticalAlign: aligns[1]\n            }\n        };\n    },\n\n    // render year\n    _renderYearText: function (calendarModel, rangeData, orient, group) {\n        var yearLabel = calendarModel.getModel('yearLabel');\n\n        if (!yearLabel.get('show')) {\n            return;\n        }\n\n        var margin = yearLabel.get('margin');\n        var pos = yearLabel.get('position');\n\n        if (!pos) {\n            pos = orient !== 'horizontal' ? 'top' : 'left';\n        }\n\n        var points = [this._tlpoints[this._tlpoints.length - 1], this._blpoints[0]];\n        var xc = (points[0][0] + points[1][0]) / 2;\n        var yc = (points[0][1] + points[1][1]) / 2;\n\n        var idx = orient === 'horizontal' ? 0 : 1;\n\n        var posPoints = {\n            top: [xc, points[idx][1]],\n            bottom: [xc, points[1 - idx][1]],\n            left: [points[1 - idx][0], yc],\n            right: [points[idx][0], yc]\n        };\n\n        var name = rangeData.start.y;\n\n        if (+rangeData.end.y > +rangeData.start.y) {\n            name = name + '-' + rangeData.end.y;\n        }\n\n        var formatter = yearLabel.get('formatter');\n\n        var params = {\n            start: rangeData.start.y,\n            end: rangeData.end.y,\n            nameMap: name\n        };\n\n        var content = this._formatterLabel(formatter, params);\n\n        var yearText = new Text({z2: 30});\n        setTextStyle(yearText.style, yearLabel, {text: content}),\n        yearText.attr(this._yearTextPositionControl(yearText, posPoints[pos], orient, pos, margin));\n\n        group.add(yearText);\n    },\n\n    _monthTextPositionControl: function (point, isCenter, orient, position, margin) {\n        var align = 'left';\n        var vAlign = 'top';\n        var x = point[0];\n        var y = point[1];\n\n        if (orient === 'horizontal') {\n            y = y + margin;\n\n            if (isCenter) {\n                align = 'center';\n            }\n\n            if (position === 'start') {\n                vAlign = 'bottom';\n            }\n        }\n        else {\n            x = x + margin;\n\n            if (isCenter) {\n                vAlign = 'middle';\n            }\n\n            if (position === 'start') {\n                align = 'right';\n            }\n        }\n\n        return {\n            x: x,\n            y: y,\n            textAlign: align,\n            textVerticalAlign: vAlign\n        };\n    },\n\n    // render month and year text\n    _renderMonthText: function (calendarModel, orient, group) {\n        var monthLabel = calendarModel.getModel('monthLabel');\n\n        if (!monthLabel.get('show')) {\n            return;\n        }\n\n        var nameMap = monthLabel.get('nameMap');\n        var margin = monthLabel.get('margin');\n        var pos = monthLabel.get('position');\n        var align = monthLabel.get('align');\n\n        var termPoints = [this._tlpoints, this._blpoints];\n\n        if (isString(nameMap)) {\n            nameMap = MONTH_TEXT[nameMap.toUpperCase()] || [];\n        }\n\n        var idx = pos === 'start' ? 0 : 1;\n        var axis = orient === 'horizontal' ? 0 : 1;\n        margin = pos === 'start' ? -margin : margin;\n        var isCenter = (align === 'center');\n\n        for (var i = 0; i < termPoints[idx].length - 1; i++) {\n\n            var tmp = termPoints[idx][i].slice();\n            var firstDay = this._firstDayOfMonth[i];\n\n            if (isCenter) {\n                var firstDayPoints = this._firstDayPoints[i];\n                tmp[axis] = (firstDayPoints[axis] + termPoints[0][i + 1][axis]) / 2;\n            }\n\n            var formatter = monthLabel.get('formatter');\n            var name = nameMap[+firstDay.m - 1];\n            var params = {\n                yyyy: firstDay.y,\n                yy: (firstDay.y + '').slice(2),\n                MM: firstDay.m,\n                M: +firstDay.m,\n                nameMap: name\n            };\n\n            var content = this._formatterLabel(formatter, params);\n\n            var monthText = new Text({z2: 30});\n            extend(\n                setTextStyle(monthText.style, monthLabel, {text: content}),\n                this._monthTextPositionControl(tmp, isCenter, orient, pos, margin)\n            );\n\n            group.add(monthText);\n        }\n    },\n\n    _weekTextPositionControl: function (point, orient, position, margin, cellSize) {\n        var align = 'center';\n        var vAlign = 'middle';\n        var x = point[0];\n        var y = point[1];\n        var isStart = position === 'start';\n\n        if (orient === 'horizontal') {\n            x = x + margin + (isStart ? 1 : -1) * cellSize[0] / 2;\n            align = isStart ? 'right' : 'left';\n        }\n        else {\n            y = y + margin + (isStart ? 1 : -1) * cellSize[1] / 2;\n            vAlign = isStart ? 'bottom' : 'top';\n        }\n\n        return {\n            x: x,\n            y: y,\n            textAlign: align,\n            textVerticalAlign: vAlign\n        };\n    },\n\n    // render weeks\n    _renderWeekText: function (calendarModel, rangeData, orient, group) {\n        var dayLabel = calendarModel.getModel('dayLabel');\n\n        if (!dayLabel.get('show')) {\n            return;\n        }\n\n        var coordSys = calendarModel.coordinateSystem;\n        var pos = dayLabel.get('position');\n        var nameMap = dayLabel.get('nameMap');\n        var margin = dayLabel.get('margin');\n        var firstDayOfWeek = coordSys.getFirstDayOfWeek();\n\n        if (isString(nameMap)) {\n            nameMap = WEEK_TEXT[nameMap.toUpperCase()] || [];\n        }\n\n        var start = coordSys.getNextNDay(\n            rangeData.end.time, (7 - rangeData.lweek)\n        ).time;\n\n        var cellSize = [coordSys.getCellWidth(), coordSys.getCellHeight()];\n        margin = parsePercent$1(margin, cellSize[orient === 'horizontal' ? 0 : 1]);\n\n        if (pos === 'start') {\n            start = coordSys.getNextNDay(\n                rangeData.start.time, -(7 + rangeData.fweek)\n            ).time;\n            margin = -margin;\n        }\n\n        for (var i = 0; i < 7; i++) {\n\n            var tmpD = coordSys.getNextNDay(start, i);\n            var point = coordSys.dataToRect([tmpD.time], false).center;\n            var day = i;\n            day = Math.abs((i + firstDayOfWeek) % 7);\n            var weekText = new Text({z2: 30});\n\n            extend(\n                setTextStyle(weekText.style, dayLabel, {text: nameMap[day]}),\n                this._weekTextPositionControl(point, orient, pos, margin, cellSize)\n            );\n            group.add(weekText);\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file calendar.js\n * @author dxh\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Model\nextendComponentModel({\n\n    type: 'title',\n\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 6,\n        show: true,\n\n        text: '',\n        // 超链接跳转\n        // link: null,\n        // 仅支持self | blank\n        target: 'blank',\n        subtext: '',\n\n        // 超链接跳转\n        // sublink: null,\n        // 仅支持self | blank\n        subtarget: 'blank',\n\n        // 'center' ¦ 'left' ¦ 'right'\n        // ¦ {number}（x坐标，单位px）\n        left: 0,\n        // 'top' ¦ 'bottom' ¦ 'center'\n        // ¦ {number}（y坐标，单位px）\n        top: 0,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right' | 'center'\n        // 默认根据 left 的位置判断是左对齐还是右对齐\n        // textAlign: null\n        //\n        // 垂直对齐\n        // 'auto' | 'top' | 'bottom' | 'middle'\n        // 默认根据 top 位置判断是上对齐还是下对齐\n        // textBaseline: null\n\n        backgroundColor: 'rgba(0,0,0,0)',\n\n        // 标题边框颜色\n        borderColor: '#ccc',\n\n        // 标题边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 标题内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // 主副标题纵向间隔，单位px，默认为10，\n        itemGap: 10,\n        textStyle: {\n            fontSize: 18,\n            fontWeight: 'bolder',\n            color: '#333'\n        },\n        subtextStyle: {\n            color: '#aaa'\n        }\n    }\n});\n\n// View\nextendComponentView({\n\n    type: 'title',\n\n    render: function (titleModel, ecModel, api) {\n        this.group.removeAll();\n\n        if (!titleModel.get('show')) {\n            return;\n        }\n\n        var group = this.group;\n\n        var textStyleModel = titleModel.getModel('textStyle');\n        var subtextStyleModel = titleModel.getModel('subtextStyle');\n\n        var textAlign = titleModel.get('textAlign');\n        var textBaseline = titleModel.get('textBaseline');\n\n        var textEl = new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: titleModel.get('text'),\n                textFill: textStyleModel.getTextColor()\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var textRect = textEl.getBoundingRect();\n\n        var subText = titleModel.get('subtext');\n        var subTextEl = new Text({\n            style: setTextStyle({}, subtextStyleModel, {\n                text: subText,\n                textFill: subtextStyleModel.getTextColor(),\n                y: textRect.height + titleModel.get('itemGap'),\n                textVerticalAlign: 'top'\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var link = titleModel.get('link');\n        var sublink = titleModel.get('sublink');\n        var triggerEvent = titleModel.get('triggerEvent', true);\n\n        textEl.silent = !link && !triggerEvent;\n        subTextEl.silent = !sublink && !triggerEvent;\n\n        if (link) {\n            textEl.on('click', function () {\n                window.open(link, '_' + titleModel.get('target'));\n            });\n        }\n        if (sublink) {\n            subTextEl.on('click', function () {\n                window.open(sublink, '_' + titleModel.get('subtarget'));\n            });\n        }\n\n        textEl.eventData = subTextEl.eventData = triggerEvent\n            ? {\n                componentType: 'title',\n                componentIndex: titleModel.componentIndex\n            }\n            : null;\n\n        group.add(textEl);\n        subText && group.add(subTextEl);\n        // If no subText, but add subTextEl, there will be an empty line.\n\n        var groupRect = group.getBoundingRect();\n        var layoutOption = titleModel.getBoxLayoutParams();\n        layoutOption.width = groupRect.width;\n        layoutOption.height = groupRect.height;\n        var layoutRect = getLayoutRect(\n            layoutOption, {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }, titleModel.get('padding')\n        );\n        // Adjust text align based on position\n        if (!textAlign) {\n            // Align left if title is on the left. center and right is same\n            textAlign = titleModel.get('left') || titleModel.get('right');\n            if (textAlign === 'middle') {\n                textAlign = 'center';\n            }\n            // Adjust layout by text align\n            if (textAlign === 'right') {\n                layoutRect.x += layoutRect.width;\n            }\n            else if (textAlign === 'center') {\n                layoutRect.x += layoutRect.width / 2;\n            }\n        }\n        if (!textBaseline) {\n            textBaseline = titleModel.get('top') || titleModel.get('bottom');\n            if (textBaseline === 'center') {\n                textBaseline = 'middle';\n            }\n            if (textBaseline === 'bottom') {\n                layoutRect.y += layoutRect.height;\n            }\n            else if (textBaseline === 'middle') {\n                layoutRect.y += layoutRect.height / 2;\n            }\n\n            textBaseline = textBaseline || 'top';\n        }\n\n        group.attr('position', [layoutRect.x, layoutRect.y]);\n        var alignStyle = {\n            textAlign: textAlign,\n            textVerticalAlign: textBaseline\n        };\n        textEl.setStyle(alignStyle);\n        subTextEl.setStyle(alignStyle);\n\n        // Render background\n        // Get groupRect again because textAlign has been changed\n        groupRect = group.getBoundingRect();\n        var padding = layoutRect.margin;\n        var style = titleModel.getItemStyle(['color', 'opacity']);\n        style.fill = titleModel.get('backgroundColor');\n        var rect = new Rect({\n            shape: {\n                x: groupRect.x - padding[3],\n                y: groupRect.y - padding[0],\n                width: groupRect.width + padding[1] + padding[3],\n                height: groupRect.height + padding[0] + padding[2],\n                r: titleModel.get('borderRadius')\n            },\n            style: style,\n            silent: true\n        });\n        subPixelOptimizeRect(rect);\n\n        group.add(rect);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('dataZoom', function () {\n    // Default 'slider' when no type specified.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'];\n// Supported coords.\nvar COORDS = ['cartesian2d', 'polar', 'singleAxis'];\n\n/**\n * @param {string} coordType\n * @return {boolean}\n */\nfunction isCoordSupported(coordType) {\n    return indexOf(COORDS, coordType) >= 0;\n}\n\n/**\n * Create \"each\" method to iterate names.\n *\n * @pubilc\n * @param  {Array.<string>} names\n * @param  {Array.<string>=} attrs\n * @return {Function}\n */\nfunction createNameEach(names, attrs) {\n    names = names.slice();\n    var capitalNames = map(names, capitalFirst);\n    attrs = (attrs || []).slice();\n    var capitalAttrs = map(attrs, capitalFirst);\n\n    return function (callback, context) {\n        each$1(names, function (name, index) {\n            var nameObj = {name: name, capital: capitalNames[index]};\n\n            for (var j = 0; j < attrs.length; j++) {\n                nameObj[attrs[j]] = name + capitalAttrs[j];\n            }\n\n            callback.call(context, nameObj);\n        });\n    };\n}\n\n/**\n * Iterate each dimension name.\n *\n * @public\n * @param {Function} callback The parameter is like:\n *                            {\n *                                name: 'angle',\n *                                capital: 'Angle',\n *                                axis: 'angleAxis',\n *                                axisIndex: 'angleAixs',\n *                                index: 'angleIndex'\n *                            }\n * @param {Object} context\n */\nvar eachAxisDim$1 = createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index', 'id']);\n\n/**\n * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'.\n * dataZoomModels and 'links' make up one or more graphics.\n * This function finds the graphic where the source dataZoomModel is in.\n *\n * @public\n * @param {Function} forEachNode Node iterator.\n * @param {Function} forEachEdgeType edgeType iterator\n * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id.\n * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}}\n */\nfunction createLinkedNodesFinder(forEachNode, forEachEdgeType, edgeIdGetter) {\n\n    return function (sourceNode) {\n        var result = {\n            nodes: [],\n            records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean).\n        };\n\n        forEachEdgeType(function (edgeType) {\n            result.records[edgeType.name] = {};\n        });\n\n        if (!sourceNode) {\n            return result;\n        }\n\n        absorb(sourceNode, result);\n\n        var existsLink;\n        do {\n            existsLink = false;\n            forEachNode(processSingleNode);\n        }\n        while (existsLink);\n\n        function processSingleNode(node) {\n            if (!isNodeAbsorded(node, result) && isLinked(node, result)) {\n                absorb(node, result);\n                existsLink = true;\n            }\n        }\n\n        return result;\n    };\n\n    function isNodeAbsorded(node, result) {\n        return indexOf(result.nodes, node) >= 0;\n    }\n\n    function isLinked(node, result) {\n        var hasLink = false;\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] && (hasLink = true);\n            });\n        });\n        return hasLink;\n    }\n\n    function absorb(node, result) {\n        result.nodes.push(node);\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] = true;\n            });\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$22 = each$1;\nvar asc$1 = asc;\n\n/**\n * Operate single axis.\n * One axis can only operated by one axis operator.\n * Different dataZoomModels may be defined to operate the same axis.\n * (i.e. 'inside' data zoom and 'slider' data zoom components)\n * So dataZoomModels share one axisProxy in that case.\n *\n * @class\n */\nvar AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._dimName = dimName;\n\n    /**\n     * @private\n     */\n    this._axisIndex = axisIndex;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._valueWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._percentWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._dataExtent;\n\n    /**\n     * {minSpan, maxSpan, minValueSpan, maxValueSpan}\n     * @private\n     * @type {Object}\n     */\n    this._minMaxSpan;\n\n    /**\n     * @readOnly\n     * @type {module: echarts/model/Global}\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @private\n     * @type {module: echarts/component/dataZoom/DataZoomModel}\n     */\n    this._dataZoomModel = dataZoomModel;\n\n    // /**\n    //  * @readOnly\n    //  * @private\n    //  */\n    // this.hasSeriesStacked;\n};\n\nAxisProxy.prototype = {\n\n    constructor: AxisProxy,\n\n    /**\n     * Whether the axisProxy is hosted by dataZoomModel.\n     *\n     * @public\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     * @return {boolean}\n     */\n    hostedBy: function (dataZoomModel) {\n        return this._dataZoomModel === dataZoomModel;\n    },\n\n    /**\n     * @return {Array.<number>} Value can only be NaN or finite value.\n     */\n    getDataValueWindow: function () {\n        return this._valueWindow.slice();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getDataPercentWindow: function () {\n        return this._percentWindow.slice();\n    },\n\n    /**\n     * @public\n     * @param {number} axisIndex\n     * @return {Array} seriesModels\n     */\n    getTargetSeriesModels: function () {\n        var seriesModels = [];\n        var ecModel = this.ecModel;\n\n        ecModel.eachSeries(function (seriesModel) {\n            if (isCoordSupported(seriesModel.get('coordinateSystem'))) {\n                var dimName = this._dimName;\n                var axisModel = ecModel.queryComponents({\n                    mainType: dimName + 'Axis',\n                    index: seriesModel.get(dimName + 'AxisIndex'),\n                    id: seriesModel.get(dimName + 'AxisId')\n                })[0];\n                if (this._axisIndex === (axisModel && axisModel.componentIndex)) {\n                    seriesModels.push(seriesModel);\n                }\n            }\n        }, this);\n\n        return seriesModels;\n    },\n\n    getAxisModel: function () {\n        return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);\n    },\n\n    getOtherAxisModel: function () {\n        var axisDim = this._dimName;\n        var ecModel = this.ecModel;\n        var axisModel = this.getAxisModel();\n        var isCartesian = axisDim === 'x' || axisDim === 'y';\n        var otherAxisDim;\n        var coordSysIndexName;\n        if (isCartesian) {\n            coordSysIndexName = 'gridIndex';\n            otherAxisDim = axisDim === 'x' ? 'y' : 'x';\n        }\n        else {\n            coordSysIndexName = 'polarIndex';\n            otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';\n        }\n        var foundOtherAxisModel;\n        ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {\n            if ((otherAxisModel.get(coordSysIndexName) || 0)\n                === (axisModel.get(coordSysIndexName) || 0)\n            ) {\n                foundOtherAxisModel = otherAxisModel;\n            }\n        });\n        return foundOtherAxisModel;\n    },\n\n    getMinMaxSpan: function () {\n        return clone(this._minMaxSpan);\n    },\n\n    /**\n     * Only calculate by given range and this._dataExtent, do not change anything.\n     *\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     */\n    calculateDataWindow: function (opt) {\n        var dataExtent = this._dataExtent;\n        var axisModel = this.getAxisModel();\n        var scale = axisModel.axis.scale;\n        var rangePropMode = this._dataZoomModel.getRangePropMode();\n        var percentExtent = [0, 100];\n        var percentWindow = [\n            opt.start,\n            opt.end\n        ];\n        var valueWindow = [];\n\n        each$22(['startValue', 'endValue'], function (prop) {\n            valueWindow.push(opt[prop] != null ? scale.parse(opt[prop]) : null);\n        });\n\n        // Normalize bound.\n        each$22([0, 1], function (idx) {\n            var boundValue = valueWindow[idx];\n            var boundPercent = percentWindow[idx];\n\n            // Notice: dataZoom is based either on `percentProp` ('start', 'end') or\n            // on `valueProp` ('startValue', 'endValue'). The former one is suitable\n            // for cases that a dataZoom component controls multiple axes with different\n            // unit or extent, and the latter one is suitable for accurate zoom by pixel\n            // (e.g., in dataZoomSelect). `valueProp` can be calculated from `percentProp`,\n            // but it is awkward that `percentProp` can not be obtained from `valueProp`\n            // accurately (because all of values that are overflow the `dataExtent` will\n            // be calculated to percent '100%'). So we have to use\n            // `dataZoom.getRangePropMode()` to mark which prop is used.\n            // `rangePropMode` is updated only when setOption or dispatchAction, otherwise\n            // it remains its original value.\n\n            if (rangePropMode[idx] === 'percent') {\n                if (boundPercent == null) {\n                    boundPercent = percentExtent[idx];\n                }\n                // Use scale.parse to math round for category or time axis.\n                boundValue = scale.parse(linearMap(\n                    boundPercent, percentExtent, dataExtent, true\n                ));\n            }\n            else {\n                // Calculating `percent` from `value` may be not accurate, because\n                // This calculation can not be inversed, because all of values that\n                // are overflow the `dataExtent` will be calculated to percent '100%'\n                boundPercent = linearMap(\n                    boundValue, dataExtent, percentExtent, true\n                );\n            }\n\n            // valueWindow[idx] = round(boundValue);\n            // percentWindow[idx] = round(boundPercent);\n            valueWindow[idx] = boundValue;\n            percentWindow[idx] = boundPercent;\n        });\n\n        return {\n            valueWindow: asc$1(valueWindow),\n            percentWindow: asc$1(percentWindow)\n        };\n    },\n\n    /**\n     * Notice: reset should not be called before series.restoreData() called,\n     * so it is recommanded to be called in \"process stage\" but not \"model init\n     * stage\".\n     *\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    reset: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var targetSeries = this.getTargetSeriesModels();\n        // Culculate data window and data extent, and record them.\n        this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries);\n\n        // this.hasSeriesStacked = false;\n        // each(targetSeries, function (series) {\n            // var data = series.getData();\n            // var dataDim = data.mapDimension(this._dimName);\n            // var stackedDimension = data.getCalculationInfo('stackedDimension');\n            // if (stackedDimension && stackedDimension === dataDim) {\n                // this.hasSeriesStacked = true;\n            // }\n        // }, this);\n\n        var dataWindow = this.calculateDataWindow(dataZoomModel.option);\n\n        this._valueWindow = dataWindow.valueWindow;\n        this._percentWindow = dataWindow.percentWindow;\n\n        setMinMaxSpan(this);\n\n        // Update axis setting then.\n        setAxisModel(this);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    restore: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        this._valueWindow = this._percentWindow = null;\n        setAxisModel(this, true);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    filterData: function (dataZoomModel, api) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var axisDim = this._dimName;\n        var seriesModels = this.getTargetSeriesModels();\n        var filterMode = dataZoomModel.get('filterMode');\n        var valueWindow = this._valueWindow;\n\n        if (filterMode === 'none') {\n            return;\n        }\n\n        // FIXME\n        // Toolbox may has dataZoom injected. And if there are stacked bar chart\n        // with NaN data, NaN will be filtered and stack will be wrong.\n        // So we need to force the mode to be set empty.\n        // In fect, it is not a big deal that do not support filterMode-'filter'\n        // when using toolbox#dataZoom, utill tooltip#dataZoom support \"single axis\n        // selection\" some day, which might need \"adapt to data extent on the\n        // otherAxis\", which is disabled by filterMode-'empty'.\n        // But currently, stack has been fixed to based on value but not index,\n        // so this is not an issue any more.\n        // var otherAxisModel = this.getOtherAxisModel();\n        // if (dataZoomModel.get('$fromToolbox')\n        //     && otherAxisModel\n        //     && otherAxisModel.hasSeriesStacked\n        // ) {\n        //     filterMode = 'empty';\n        // }\n\n        // TODO\n        // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet.\n\n        each$22(seriesModels, function (seriesModel) {\n            var seriesData = seriesModel.getData();\n            var dataDims = seriesData.mapDimension(axisDim, true);\n\n            if (!dataDims.length) {\n                return;\n            }\n\n            if (filterMode === 'weakFilter') {\n                seriesData.filterSelf(function (dataIndex) {\n                    var leftOut;\n                    var rightOut;\n                    var hasValue;\n                    for (var i = 0; i < dataDims.length; i++) {\n                        var value = seriesData.get(dataDims[i], dataIndex);\n                        var thisHasValue = !isNaN(value);\n                        var thisLeftOut = value < valueWindow[0];\n                        var thisRightOut = value > valueWindow[1];\n                        if (thisHasValue && !thisLeftOut && !thisRightOut) {\n                            return true;\n                        }\n                        thisHasValue && (hasValue = true);\n                        thisLeftOut && (leftOut = true);\n                        thisRightOut && (rightOut = true);\n                    }\n                    // If both left out and right out, do not filter.\n                    return hasValue && leftOut && rightOut;\n                });\n            }\n            else {\n                each$22(dataDims, function (dim) {\n                    if (filterMode === 'empty') {\n                        seriesModel.setData(\n                            seriesData.map(dim, function (value) {\n                                return !isInWindow(value) ? NaN : value;\n                            })\n                        );\n                    }\n                    else {\n                        var range = {};\n                        range[dim] = valueWindow;\n\n                        // console.time('select');\n                        seriesData.selectRange(range);\n                        // console.timeEnd('select');\n                    }\n                });\n            }\n\n            each$22(dataDims, function (dim) {\n                seriesData.setApproximateExtent(valueWindow, dim);\n            });\n        });\n\n        function isInWindow(value) {\n            return value >= valueWindow[0] && value <= valueWindow[1];\n        }\n    }\n};\n\nfunction calculateDataExtent(axisProxy, axisDim, seriesModels) {\n    var dataExtent = [Infinity, -Infinity];\n\n    each$22(seriesModels, function (seriesModel) {\n        var seriesData = seriesModel.getData();\n        if (seriesData) {\n            each$22(seriesData.mapDimension(axisDim, true), function (dim) {\n                var seriesExtent = seriesData.getApproximateExtent(dim);\n                seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);\n                seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);\n            });\n        }\n    });\n\n    if (dataExtent[1] < dataExtent[0]) {\n        dataExtent = [NaN, NaN];\n    }\n\n    // It is important to get \"consistent\" extent when more then one axes is\n    // controlled by a `dataZoom`, otherwise those axes will not be synchronized\n    // when zooming. But it is difficult to know what is \"consistent\", considering\n    // axes have different type or even different meanings (For example, two\n    // time axes are used to compare data of the same date in different years).\n    // So basically dataZoom just obtains extent by series.data (in category axis\n    // extent can be obtained from axis.data).\n    // Nevertheless, user can set min/max/scale on axes to make extent of axes\n    // consistent.\n    fixExtentByAxis(axisProxy, dataExtent);\n\n    return dataExtent;\n}\n\nfunction fixExtentByAxis(axisProxy, dataExtent) {\n    var axisModel = axisProxy.getAxisModel();\n    var min = axisModel.getMin(true);\n\n    // For category axis, if min/max/scale are not set, extent is determined\n    // by axis.data by default.\n    var isCategoryAxis = axisModel.get('type') === 'category';\n    var axisDataLen = isCategoryAxis && axisModel.getCategories().length;\n\n    if (min != null && min !== 'dataMin' && typeof min !== 'function') {\n        dataExtent[0] = min;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[0] = axisDataLen > 0 ? 0 : NaN;\n    }\n\n    var max = axisModel.getMax(true);\n    if (max != null && max !== 'dataMax' && typeof max !== 'function') {\n        dataExtent[1] = max;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[1] = axisDataLen > 0 ? axisDataLen - 1 : NaN;\n    }\n\n    if (!axisModel.get('scale', true)) {\n        dataExtent[0] > 0 && (dataExtent[0] = 0);\n        dataExtent[1] < 0 && (dataExtent[1] = 0);\n    }\n\n    // For value axis, if min/max/scale are not set, we just use the extent obtained\n    // by series data, which may be a little different from the extent calculated by\n    // `axisHelper.getScaleExtent`. But the different just affects the experience a\n    // little when zooming. So it will not be fixed until some users require it strongly.\n\n    return dataExtent;\n}\n\nfunction setAxisModel(axisProxy, isRestore) {\n    var axisModel = axisProxy.getAxisModel();\n\n    var percentWindow = axisProxy._percentWindow;\n    var valueWindow = axisProxy._valueWindow;\n\n    if (!percentWindow) {\n        return;\n    }\n\n    // [0, 500]: arbitrary value, guess axis extent.\n    var precision = getPixelPrecision(valueWindow, [0, 500]);\n    precision = Math.min(precision, 20);\n    // isRestore or isFull\n    var useOrigin = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);\n\n    axisModel.setRange(\n        useOrigin ? null : +valueWindow[0].toFixed(precision),\n        useOrigin ? null : +valueWindow[1].toFixed(precision)\n    );\n}\n\nfunction setMinMaxSpan(axisProxy) {\n    var minMaxSpan = axisProxy._minMaxSpan = {};\n    var dataZoomModel = axisProxy._dataZoomModel;\n\n    each$22(['min', 'max'], function (minMax) {\n        minMaxSpan[minMax + 'Span'] = dataZoomModel.get(minMax + 'Span');\n\n        // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan\n        var valueSpan = dataZoomModel.get(minMax + 'ValueSpan');\n\n        if (valueSpan != null) {\n            minMaxSpan[minMax + 'ValueSpan'] = valueSpan;\n            valueSpan = axisProxy.getAxisModel().axis.scale.parse(valueSpan);\n\n            if (valueSpan != null) {\n                var dataExtent = axisProxy._dataExtent;\n                minMaxSpan[minMax + 'Span'] = linearMap(\n                    dataExtent[0] + valueSpan, dataExtent, [0, 100], true\n                );\n            }\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$21 = each$1;\nvar eachAxisDim = eachAxisDim$1;\n\nvar DataZoomModel = extendComponentModel({\n\n    type: 'dataZoom',\n\n    dependencies: [\n        'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series'\n    ],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 4,                   // Higher than normal component (z: 2).\n        orient: null,           // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.\n        xAxisIndex: null,       // Default the first horizontal category axis.\n        yAxisIndex: null,       // Default the first vertical category axis.\n\n        filterMode: 'filter',   // Possible values: 'filter' or 'empty' or 'weakFilter'.\n                                // 'filter': data items which are out of window will be removed. This option is\n                                //          applicable when filtering outliers. For each data item, it will be\n                                //          filtered if one of the relevant dimensions is out of the window.\n                                // 'weakFilter': data items which are out of window will be removed. This option\n                                //          is applicable when filtering outliers. For each data item, it will be\n                                //          filtered only if all  of the relevant dimensions are out of the same\n                                //          side of the window.\n                                // 'empty': data items which are out of window will be set to empty.\n                                //          This option is applicable when user should not neglect\n                                //          that there are some data items out of window.\n                                // 'none': Do not filter.\n                                // Taking line chart as an example, line will be broken in\n                                // the filtered points when filterModel is set to 'empty', but\n                                // be connected when set to 'filter'.\n\n        throttle: null,         // Dispatch action by the fixed rate, avoid frequency.\n                                // default 100. Do not throttle when use null/undefined.\n                                // If animation === true and animationDurationUpdate > 0,\n                                // default value is 100, otherwise 20.\n        start: 0,               // Start percent. 0 ~ 100\n        end: 100,               // End percent. 0 ~ 100\n        startValue: null,       // Start value. If startValue specified, start is ignored.\n        endValue: null,         // End value. If endValue specified, end is ignored.\n        minSpan: null,          // 0 ~ 100\n        maxSpan: null,          // 0 ~ 100\n        minValueSpan: null,     // The range of dataZoom can not be smaller than that.\n        maxValueSpan: null,     // The range of dataZoom can not be larger than that.\n        rangeMode: null         // Array, can be 'value' or 'percent'.\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * key like x_0, y_1\n         * @private\n         * @type {Object}\n         */\n        this._dataIntervalByAxis = {};\n\n        /**\n         * @private\n         */\n        this._dataInfo = {};\n\n        /**\n         * key like x_0, y_1\n         * @private\n         */\n        this._axisProxies = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * @private\n         */\n        this._autoThrottle = true;\n\n        /**\n         * 'percent' or 'value'\n         * @private\n         */\n        this._rangePropMode = ['percent', 'percent'];\n\n        var rawOption = retrieveRaw(option);\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var rawOption = retrieveRaw(newOption);\n\n        //FIX #2591\n        merge(this.option, newOption, true);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @protected\n     */\n    doInit: function (rawOption) {\n        var thisOption = this.option;\n\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        this._setDefaultThrottle(rawOption);\n\n        updateRangeUse(this, rawOption);\n\n        each$21([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n            // start/end has higher priority over startValue/endValue if they\n            // both set, but we should make chart.setOption({endValue: 1000})\n            // effective, rather than chart.setOption({endValue: 1000, end: null}).\n            if (this._rangePropMode[index] === 'value') {\n                thisOption[names[0]] = null;\n            }\n            // Otherwise do nothing and use the merge result.\n        }, this);\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this._resetTarget();\n\n        this._giveAxisProxies();\n    },\n\n    /**\n     * @private\n     */\n    _giveAxisProxies: function () {\n        var axisProxies = this._axisProxies;\n\n        this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {\n            var axisModel = this.dependentModels[dimNames.axis][axisIndex];\n\n            // If exists, share axisProxy with other dataZoomModels.\n            var axisProxy = axisModel.__dzAxisProxy || (\n                // Use the first dataZoomModel as the main model of axisProxy.\n                axisModel.__dzAxisProxy = new AxisProxy(\n                    dimNames.name, axisIndex, this, ecModel\n                )\n            );\n            // FIXME\n            // dispose __dzAxisProxy\n\n            axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetTarget: function () {\n        var thisOption = this.option;\n\n        var autoMode = this._judgeAutoMode();\n\n        eachAxisDim(function (dimNames) {\n            var axisIndexName = dimNames.axisIndex;\n            thisOption[axisIndexName] = normalizeToArray(\n                thisOption[axisIndexName]\n            );\n        }, this);\n\n        if (autoMode === 'axisIndex') {\n            this._autoSetAxisIndex();\n        }\n        else if (autoMode === 'orient') {\n            this._autoSetOrient();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _judgeAutoMode: function () {\n        // Auto set only works for setOption at the first time.\n        // The following is user's reponsibility. So using merged\n        // option is OK.\n        var thisOption = this.option;\n\n        var hasIndexSpecified = false;\n        eachAxisDim(function (dimNames) {\n            // When user set axisIndex as a empty array, we think that user specify axisIndex\n            // but do not want use auto mode. Because empty array may be encountered when\n            // some error occured.\n            if (thisOption[dimNames.axisIndex] != null) {\n                hasIndexSpecified = true;\n            }\n        }, this);\n\n        var orient = thisOption.orient;\n\n        if (orient == null && hasIndexSpecified) {\n            return 'orient';\n        }\n        else if (!hasIndexSpecified) {\n            if (orient == null) {\n                thisOption.orient = 'horizontal';\n            }\n            return 'axisIndex';\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetAxisIndex: function () {\n        var autoAxisIndex = true;\n        var orient = this.get('orient', true);\n        var thisOption = this.option;\n        var dependentModels = this.dependentModels;\n\n        if (autoAxisIndex) {\n            // Find axis that parallel to dataZoom as default.\n            var dimName = orient === 'vertical' ? 'y' : 'x';\n\n            if (dependentModels[dimName + 'Axis'].length) {\n                thisOption[dimName + 'AxisIndex'] = [0];\n                autoAxisIndex = false;\n            }\n            else {\n                each$21(dependentModels.singleAxis, function (singleAxisModel) {\n                    if (autoAxisIndex && singleAxisModel.get('orient', true) === orient) {\n                        thisOption.singleAxisIndex = [singleAxisModel.componentIndex];\n                        autoAxisIndex = false;\n                    }\n                });\n            }\n        }\n\n        if (autoAxisIndex) {\n            // Find the first category axis as default. (consider polar)\n            eachAxisDim(function (dimNames) {\n                if (!autoAxisIndex) {\n                    return;\n                }\n                var axisIndices = [];\n                var axisModels = this.dependentModels[dimNames.axis];\n                if (axisModels.length && !axisIndices.length) {\n                    for (var i = 0, len = axisModels.length; i < len; i++) {\n                        if (axisModels[i].get('type') === 'category') {\n                            axisIndices.push(i);\n                        }\n                    }\n                }\n                thisOption[dimNames.axisIndex] = axisIndices;\n                if (axisIndices.length) {\n                    autoAxisIndex = false;\n                }\n            }, this);\n        }\n\n        if (autoAxisIndex) {\n            // FIXME\n            // 这里是兼容ec2的写法（没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制），\n            // 但是实际是否需要Grid.js#getScaleByOption来判断（考虑time，log等axis type）？\n\n            // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,\n            // dataZoom component auto adopts series that reference to\n            // both xAxis and yAxis which type is 'value'.\n            this.ecModel.eachSeries(function (seriesModel) {\n                if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {\n                    eachAxisDim(function (dimNames) {\n                        var axisIndices = thisOption[dimNames.axisIndex];\n\n                        var axisIndex = seriesModel.get(dimNames.axisIndex);\n                        var axisId = seriesModel.get(dimNames.axisId);\n\n                        var axisModel = seriesModel.ecModel.queryComponents({\n                            mainType: dimNames.axis,\n                            index: axisIndex,\n                            id: axisId\n                        })[0];\n\n                        if (__DEV__) {\n                            if (!axisModel) {\n                                throw new Error(\n                                    dimNames.axis + ' \"' + retrieve(\n                                        axisIndex,\n                                        axisId,\n                                        0\n                                    ) + '\" not found'\n                                );\n                            }\n                        }\n                        axisIndex = axisModel.componentIndex;\n\n                        if (indexOf(axisIndices, axisIndex) < 0) {\n                            axisIndices.push(axisIndex);\n                        }\n                    });\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetOrient: function () {\n        var dim;\n\n        // Find the first axis\n        this.eachTargetAxis(function (dimNames) {\n            !dim && (dim = dimNames.name);\n        }, this);\n\n        this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';\n    },\n\n    /**\n     * @private\n     */\n    _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {\n        // FIXME\n        // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。\n        // 例如series.type === scatter时。\n\n        var is = true;\n        eachAxisDim(function (dimNames) {\n            var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);\n            var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];\n\n            if (!axisModel || axisModel.get('type') !== axisType) {\n                is = false;\n            }\n        }, this);\n        return is;\n    },\n\n    /**\n     * @private\n     */\n    _setDefaultThrottle: function (rawOption) {\n        // When first time user set throttle, auto throttle ends.\n        if (rawOption.hasOwnProperty('throttle')) {\n            this._autoThrottle = false;\n        }\n        if (this._autoThrottle) {\n            var globalOption = this.ecModel.option;\n            this.option.throttle\n                = (globalOption.animation && globalOption.animationDurationUpdate > 0)\n                ? 100 : 20;\n        }\n    },\n\n    /**\n     * @public\n     */\n    getFirstTargetAxisModel: function () {\n        var firstAxisModel;\n        eachAxisDim(function (dimNames) {\n            if (firstAxisModel == null) {\n                var indices = this.get(dimNames.axisIndex);\n                if (indices.length) {\n                    firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];\n                }\n            }\n        }, this);\n\n        return firstAxisModel;\n    },\n\n    /**\n     * @public\n     * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel\n     */\n    eachTargetAxis: function (callback, context) {\n        var ecModel = this.ecModel;\n        eachAxisDim(function (dimNames) {\n            each$21(\n                this.get(dimNames.axisIndex),\n                function (axisIndex) {\n                    callback.call(context, dimNames, axisIndex, this, ecModel);\n                },\n                this\n            );\n        }, this);\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/component/dataZoom/AxisProxy} If not found, return null/undefined.\n     */\n    getAxisProxy: function (dimName, axisIndex) {\n        return this._axisProxies[dimName + '_' + axisIndex];\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/model/Model} If not found, return null/undefined.\n     */\n    getAxisModel: function (dimName, axisIndex) {\n        var axisProxy = this.getAxisProxy(dimName, axisIndex);\n        return axisProxy && axisProxy.getAxisModel();\n    },\n\n    /**\n     * If not specified, set to undefined.\n     *\n     * @public\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     * @param {boolean} [ignoreUpdateRangeUsg=false]\n     */\n    setRawRange: function (opt, ignoreUpdateRangeUsg) {\n        var option = this.option;\n        each$21([['start', 'startValue'], ['end', 'endValue']], function (names) {\n            // If only one of 'start' and 'startValue' is not null/undefined, the other\n            // should be cleared, which enable clear the option.\n            // If both of them are not set, keep option with the original value, which\n            // enable use only set start but not set end when calling `dispatchAction`.\n            // The same as 'end' and 'endValue'.\n            if (opt[names[0]] != null || opt[names[1]] != null) {\n                option[names[0]] = opt[names[0]];\n                option[names[1]] = opt[names[1]];\n            }\n        }, this);\n\n        !ignoreUpdateRangeUsg && updateRangeUse(this, opt);\n    },\n\n    /**\n     * @public\n     * @return {Array.<number>} [startPercent, endPercent]\n     */\n    getPercentRange: function () {\n        var axisProxy = this.findRepresentativeAxisProxy();\n        if (axisProxy) {\n            return axisProxy.getDataPercentWindow();\n        }\n    },\n\n    /**\n     * @public\n     * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);\n     *\n     * @param {string} [axisDimName]\n     * @param {number} [axisIndex]\n     * @return {Array.<number>} [startValue, endValue] value can only be '-' or finite number.\n     */\n    getValueRange: function (axisDimName, axisIndex) {\n        if (axisDimName == null && axisIndex == null) {\n            var axisProxy = this.findRepresentativeAxisProxy();\n            if (axisProxy) {\n                return axisProxy.getDataValueWindow();\n            }\n        }\n        else {\n            return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();\n        }\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/model/Model} [axisModel] If axisModel given, find axisProxy\n     *      corresponding to the axisModel\n     * @return {module:echarts/component/dataZoom/AxisProxy}\n     */\n    findRepresentativeAxisProxy: function (axisModel) {\n        if (axisModel) {\n            return axisModel.__dzAxisProxy;\n        }\n\n        // Find the first hosted axisProxy\n        var axisProxies = this._axisProxies;\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n\n        // If no hosted axis find not hosted axisProxy.\n        // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,\n        // and the option.start or option.end settings are different. The percentRange\n        // should follow axisProxy.\n        // (We encounter this problem in toolbox data zoom.)\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n    },\n\n    /**\n     * @return {Array.<string>}\n     */\n    getRangePropMode: function () {\n        return this._rangePropMode.slice();\n    }\n\n});\n\nfunction retrieveRaw(option) {\n    var ret = {};\n    each$21(\n        ['start', 'end', 'startValue', 'endValue', 'throttle'],\n        function (name) {\n            option.hasOwnProperty(name) && (ret[name] = option[name]);\n        }\n    );\n    return ret;\n}\n\nfunction updateRangeUse(dataZoomModel, rawOption) {\n    var rangePropMode = dataZoomModel._rangePropMode;\n    var rangeModeInOption = dataZoomModel.get('rangeMode');\n\n    each$21([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n        var percentSpecified = rawOption[names[0]] != null;\n        var valueSpecified = rawOption[names[1]] != null;\n        if (percentSpecified && !valueSpecified) {\n            rangePropMode[index] = 'percent';\n        }\n        else if (!percentSpecified && valueSpecified) {\n            rangePropMode[index] = 'value';\n        }\n        else if (rangeModeInOption) {\n            rangePropMode[index] = rangeModeInOption[index];\n        }\n        else if (percentSpecified) { // percentSpecified && valueSpecified\n            rangePropMode[index] = 'percent';\n        }\n        // else remain its original setting.\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DataZoomView = Component.extend({\n\n    type: 'dataZoom',\n\n    render: function (dataZoomModel, ecModel, api, payload) {\n        this.dataZoomModel = dataZoomModel;\n        this.ecModel = ecModel;\n        this.api = api;\n    },\n\n    /**\n     * Find the first target coordinate system.\n     *\n     * @protected\n     * @return {Object} {\n     *                   grid: [\n     *                       {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},\n     *                       {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},\n     *                       ...\n     *                   ],  // cartesians must not be null/undefined.\n     *                   polar: [\n     *                       {model: coord0, axisModels: [axis4], coordIndex: 0},\n     *                       ...\n     *                   ],  // polars must not be null/undefined.\n     *                   singleAxis: [\n     *                       {model: coord0, axisModels: [], coordIndex: 0}\n     *                   ]\n     */\n    getTargetCoordInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var ecModel = this.ecModel;\n        var coordSysLists = {};\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);\n            if (axisModel) {\n                var coordModel = axisModel.getCoordSysModel();\n                coordModel && save(\n                    coordModel,\n                    axisModel,\n                    coordSysLists[coordModel.mainType] || (coordSysLists[coordModel.mainType] = []),\n                    coordModel.componentIndex\n                );\n            }\n        }, this);\n\n        function save(coordModel, axisModel, store, coordIndex) {\n            var item;\n            for (var i = 0; i < store.length; i++) {\n                if (store[i].model === coordModel) {\n                    item = store[i];\n                    break;\n                }\n            }\n            if (!item) {\n                store.push(item = {\n                    model: coordModel, axisModels: [], coordIndex: coordIndex\n                });\n            }\n            item.axisModels.push(axisModel);\n        }\n\n        return coordSysLists;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderZoomModel = DataZoomModel.extend({\n\n    type: 'dataZoom.slider',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        // ph => placeholder. Using placehoder here because\n        // deault value can only be drived in view stage.\n        right: 'ph',  // Default align to grid rect.\n        top: 'ph',    // Default align to grid rect.\n        width: 'ph',  // Default align to grid rect.\n        height: 'ph', // Default align to grid rect.\n        left: null,   // Default align to grid rect.\n        bottom: null, // Default align to grid rect.\n\n        backgroundColor: 'rgba(47,69,84,0)',    // Background of slider zoom component.\n        // dataBackgroundColor: '#ddd',         // Background coor of data shadow and border of box,\n                                                // highest priority, remain for compatibility of\n                                                // previous version, but not recommended any more.\n        dataBackground: {\n            lineStyle: {\n                color: '#2f4554',\n                width: 0.5,\n                opacity: 0.3\n            },\n            areaStyle: {\n                color: 'rgba(47,69,84,0.3)',\n                opacity: 0.3\n            }\n        },\n        borderColor: '#ddd',                    // border color of the box. For compatibility,\n                                                // if dataBackgroundColor is set, borderColor\n                                                // is ignored.\n\n        fillerColor: 'rgba(167,183,204,0.4)',     // Color of selected area.\n        // handleColor: 'rgba(89,170,216,0.95)',     // Color of handle.\n        // handleIcon: 'path://M4.9,17.8c0-1.4,4.5-10.5,5.5-12.4c0-0.1,0.6-1.1,0.9-1.1c0.4,0,0.9,1,0.9,1.1c1.1,2.2,5.4,11,5.4,12.4v17.8c0,1.5-0.6,2.1-1.3,2.1H6.1c-0.7,0-1.3-0.6-1.3-2.1V17.8z',\n        /* eslint-disable */\n        handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z',\n        /* eslint-enable */\n        // Percent of the slider height\n        handleSize: '100%',\n\n        handleStyle: {\n            color: '#a7b7cc'\n        },\n\n        labelPrecision: null,\n        labelFormatter: null,\n        showDetail: true,\n        showDataShadow: 'auto',                 // Default auto decision.\n        realtime: true,\n        zoomLock: false,                        // Whether disable zoom.\n        textStyle: {\n            color: '#333'\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Rect$2 = Rect;\nvar linearMap$1 = linearMap;\nvar asc$2 = asc;\nvar bind$4 = bind;\nvar each$23 = each$1;\n\n// Constants\nvar DEFAULT_LOCATION_EDGE_GAP = 7;\nvar DEFAULT_FRAME_BORDER_WIDTH = 1;\nvar DEFAULT_FILLER_SIZE = 30;\nvar HORIZONTAL = 'horizontal';\nvar VERTICAL = 'vertical';\nvar LABEL_GAP = 5;\nvar SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];\n\nvar SliderZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.slider',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        this._displayables = {};\n\n        /**\n         * @private\n         * @type {string}\n         */\n        this._orient;\n\n        /**\n         * [0, 100]\n         * @private\n         */\n        this._range;\n\n        /**\n         * [coord of the first handle, coord of the second handle]\n         * @private\n         */\n        this._handleEnds;\n\n        /**\n         * [length, thick]\n         * @private\n         * @type {Array.<number>}\n         */\n        this._size;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleWidth;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleHeight;\n\n        /**\n         * @private\n         */\n        this._location;\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._dataShadowInfo;\n\n        this.api = api;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        SliderZoomView.superApply(this, 'render', arguments);\n\n        createOrUpdate(\n            this,\n            '_dispatchZoomAction',\n            this.dataZoomModel.get('throttle'),\n            'fixRate'\n        );\n\n        this._orient = dataZoomModel.get('orient');\n\n        if (this.dataZoomModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        // Notice: this._resetInterval() should not be executed when payload.type\n        // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'\n        // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,\n        if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {\n            this._buildView();\n        }\n\n        this._updateView();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        SliderZoomView.superApply(this, 'remove', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        SliderZoomView.superApply(this, 'dispose', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    _buildView: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        this._resetLocation();\n        this._resetInterval();\n\n        var barGroup = this._displayables.barGroup = new Group();\n\n        this._renderBackground();\n\n        this._renderHandle();\n\n        this._renderDataShadow();\n\n        thisGroup.add(barGroup);\n\n        this._positionGroup();\n    },\n\n    /**\n     * @private\n     */\n    _resetLocation: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var api = this.api;\n\n        // If some of x/y/width/height are not specified,\n        // auto-adapt according to target grid.\n        var coordRect = this._findCoordRect();\n        var ecSize = {width: api.getWidth(), height: api.getHeight()};\n        // Default align by coordinate system rect.\n        var positionInfo = this._orient === HORIZONTAL\n            ? {\n                // Why using 'right', because right should be used in vertical,\n                // and it is better to be consistent for dealing with position param merge.\n                right: ecSize.width - coordRect.x - coordRect.width,\n                top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),\n                width: coordRect.width,\n                height: DEFAULT_FILLER_SIZE\n            }\n            : { // vertical\n                right: DEFAULT_LOCATION_EDGE_GAP,\n                top: coordRect.y,\n                width: DEFAULT_FILLER_SIZE,\n                height: coordRect.height\n            };\n\n        // Do not write back to option and replace value 'ph', because\n        // the 'ph' value should be recalculated when resize.\n        var layoutParams = getLayoutParams(dataZoomModel.option);\n\n        // Replace the placeholder value.\n        each$1(['right', 'top', 'width', 'height'], function (name) {\n            if (layoutParams[name] === 'ph') {\n                layoutParams[name] = positionInfo[name];\n            }\n        });\n\n        var layoutRect = getLayoutRect(\n            layoutParams,\n            ecSize,\n            dataZoomModel.padding\n        );\n\n        this._location = {x: layoutRect.x, y: layoutRect.y};\n        this._size = [layoutRect.width, layoutRect.height];\n        this._orient === VERTICAL && this._size.reverse();\n    },\n\n    /**\n     * @private\n     */\n    _positionGroup: function () {\n        var thisGroup = this.group;\n        var location = this._location;\n        var orient = this._orient;\n\n        // Just use the first axis to determine mapping.\n        var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();\n        var inverse = targetAxisModel && targetAxisModel.get('inverse');\n\n        var barGroup = this._displayables.barGroup;\n        var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;\n\n        // Transform barGroup.\n        barGroup.attr(\n            (orient === HORIZONTAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, 1] : [1, -1]}\n            : (orient === HORIZONTAL && inverse)\n            ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}\n            : (orient === VERTICAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}\n            // Dont use Math.PI, considering shadow direction.\n            : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}\n        );\n\n        // Position barGroup\n        var rect = thisGroup.getBoundingRect([barGroup]);\n        thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]);\n    },\n\n    /**\n     * @private\n     */\n    _getViewExtent: function () {\n        return [0, this._size[0]];\n    },\n\n    _renderBackground: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var size = this._size;\n        var barGroup = this._displayables.barGroup;\n\n        barGroup.add(new Rect$2({\n            silent: true,\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: dataZoomModel.get('backgroundColor')\n            },\n            z2: -40\n        }));\n\n        // Click panel, over shadow, below handles.\n        barGroup.add(new Rect$2({\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: 'transparent'\n            },\n            z2: 0,\n            onclick: bind(this._onClickPanelClick, this)\n        }));\n    },\n\n    _renderDataShadow: function () {\n        var info = this._dataShadowInfo = this._prepareDataShadowInfo();\n\n        if (!info) {\n            return;\n        }\n\n        var size = this._size;\n        var seriesModel = info.series;\n        var data = seriesModel.getRawData();\n\n        var otherDim = seriesModel.getShadowDim\n            ? seriesModel.getShadowDim() // @see candlestick\n            : info.otherDim;\n\n        if (otherDim == null) {\n            return;\n        }\n\n        var otherDataExtent = data.getDataExtent(otherDim);\n        // Nice extent.\n        var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;\n        otherDataExtent = [\n            otherDataExtent[0] - otherOffset,\n            otherDataExtent[1] + otherOffset\n        ];\n        var otherShadowExtent = [0, size[1]];\n\n        var thisShadowExtent = [0, size[0]];\n\n        var areaPoints = [[size[0], 0], [0, 0]];\n        var linePoints = [];\n        var step = thisShadowExtent[1] / (data.count() - 1);\n        var thisCoord = 0;\n\n        // Optimize for large data shadow\n        var stride = Math.round(data.count() / size[0]);\n        var lastIsEmpty;\n        data.each([otherDim], function (value, index) {\n            if (stride > 0 && (index % stride)) {\n                thisCoord += step;\n                return;\n            }\n\n            // FIXME\n            // Should consider axis.min/axis.max when drawing dataShadow.\n\n            // FIXME\n            // 应该使用统一的空判断？还是在list里进行空判断？\n            var isEmpty = value == null || isNaN(value) || value === '';\n            // See #4235.\n            var otherCoord = isEmpty\n                ? 0 : linearMap$1(value, otherDataExtent, otherShadowExtent, true);\n\n            // Attempt to draw data shadow precisely when there are empty value.\n            if (isEmpty && !lastIsEmpty && index) {\n                areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]);\n                linePoints.push([linePoints[linePoints.length - 1][0], 0]);\n            }\n            else if (!isEmpty && lastIsEmpty) {\n                areaPoints.push([thisCoord, 0]);\n                linePoints.push([thisCoord, 0]);\n            }\n\n            areaPoints.push([thisCoord, otherCoord]);\n            linePoints.push([thisCoord, otherCoord]);\n\n            thisCoord += step;\n            lastIsEmpty = isEmpty;\n        });\n\n        var dataZoomModel = this.dataZoomModel;\n        // var dataBackgroundModel = dataZoomModel.getModel('dataBackground');\n        this._displayables.barGroup.add(new Polygon({\n            shape: {points: areaPoints},\n            style: defaults(\n                {fill: dataZoomModel.get('dataBackgroundColor')},\n                dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle()\n            ),\n            silent: true,\n            z2: -20\n        }));\n        this._displayables.barGroup.add(new Polyline({\n            shape: {points: linePoints},\n            style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(),\n            silent: true,\n            z2: -19\n        }));\n    },\n\n    _prepareDataShadowInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var showDataShadow = dataZoomModel.get('showDataShadow');\n\n        if (showDataShadow === false) {\n            return;\n        }\n\n        // Find a representative series.\n        var result;\n        var ecModel = this.ecModel;\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var seriesModels = dataZoomModel\n                .getAxisProxy(dimNames.name, axisIndex)\n                .getTargetSeriesModels();\n\n            each$1(seriesModels, function (seriesModel) {\n                if (result) {\n                    return;\n                }\n\n                if (showDataShadow !== true && indexOf(\n                        SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')\n                    ) < 0\n                ) {\n                    return;\n                }\n\n                var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;\n                var otherDim = getOtherDim(dimNames.name);\n                var otherAxisInverse;\n                var coordSys = seriesModel.coordinateSystem;\n\n                if (otherDim != null && coordSys.getOtherAxis) {\n                    otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;\n                }\n\n                otherDim = seriesModel.getData().mapDimension(otherDim);\n\n                result = {\n                    thisAxis: thisAxis,\n                    series: seriesModel,\n                    thisDim: dimNames.name,\n                    otherDim: otherDim,\n                    otherAxisInverse: otherAxisInverse\n                };\n\n            }, this);\n\n        }, this);\n\n        return result;\n    },\n\n    _renderHandle: function () {\n        var displaybles = this._displayables;\n        var handles = displaybles.handles = [];\n        var handleLabels = displaybles.handleLabels = [];\n        var barGroup = this._displayables.barGroup;\n        var size = this._size;\n        var dataZoomModel = this.dataZoomModel;\n\n        barGroup.add(displaybles.filler = new Rect$2({\n            draggable: true,\n            cursor: getCursor(this._orient),\n            drift: bind$4(this._onDragMove, this, 'all'),\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragstart: bind$4(this._showDataInfo, this, true),\n            ondragend: bind$4(this._onDragEnd, this),\n            onmouseover: bind$4(this._showDataInfo, this, true),\n            onmouseout: bind$4(this._showDataInfo, this, false),\n            style: {\n                fill: dataZoomModel.get('fillerColor'),\n                textPosition: 'inside'\n            }\n        }));\n\n        // Frame border.\n        barGroup.add(new Rect$2(subPixelOptimizeRect({\n            silent: true,\n            shape: {\n                x: 0,\n                y: 0,\n                width: size[0],\n                height: size[1]\n            },\n            style: {\n                stroke: dataZoomModel.get('dataBackgroundColor')\n                    || dataZoomModel.get('borderColor'),\n                lineWidth: DEFAULT_FRAME_BORDER_WIDTH,\n                fill: 'rgba(0,0,0,0)'\n            }\n        })));\n\n        each$23([0, 1], function (handleIndex) {\n            var path = createIcon(\n                dataZoomModel.get('handleIcon'),\n                {\n                    cursor: getCursor(this._orient),\n                    draggable: true,\n                    drift: bind$4(this._onDragMove, this, handleIndex),\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    ondragend: bind$4(this._onDragEnd, this),\n                    onmouseover: bind$4(this._showDataInfo, this, true),\n                    onmouseout: bind$4(this._showDataInfo, this, false)\n                },\n                {x: -1, y: 0, width: 2, height: 2}\n            );\n\n            var bRect = path.getBoundingRect();\n            this._handleHeight = parsePercent$1(dataZoomModel.get('handleSize'), this._size[1]);\n            this._handleWidth = bRect.width / bRect.height * this._handleHeight;\n\n            path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());\n            var handleColor = dataZoomModel.get('handleColor');\n            // Compatitable with previous version\n            if (handleColor != null) {\n                path.style.fill = handleColor;\n            }\n\n            barGroup.add(handles[handleIndex] = path);\n\n            var textStyleModel = dataZoomModel.textStyleModel;\n\n            this.group.add(\n                handleLabels[handleIndex] = new Text({\n                silent: true,\n                invisible: true,\n                style: {\n                    x: 0, y: 0, text: '',\n                    textVerticalAlign: 'middle',\n                    textAlign: 'center',\n                    textFill: textStyleModel.getTextColor(),\n                    textFont: textStyleModel.getFont()\n                },\n                z2: 10\n            }));\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var range = this._range = this.dataZoomModel.getPercentRange();\n        var viewExtent = this._getViewExtent();\n\n        this._handleEnds = [\n            linearMap$1(range[0], [0, 100], viewExtent, true),\n            linearMap$1(range[1], [0, 100], viewExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} delta\n     * @return {boolean} changed\n     */\n    _updateInterval: function (handleIndex, delta) {\n        var dataZoomModel = this.dataZoomModel;\n        var handleEnds = this._handleEnds;\n        var viewExtend = this._getViewExtent();\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n        var percentExtent = [0, 100];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            viewExtend,\n            dataZoomModel.get('zoomLock') ? 'all' : handleIndex,\n            minMaxSpan.minSpan != null\n                ? linearMap$1(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null,\n            minMaxSpan.maxSpan != null\n                ? linearMap$1(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null\n        );\n\n        var lastRange = this._range;\n        var range = this._range = asc$2([\n            linearMap$1(handleEnds[0], viewExtend, percentExtent, true),\n            linearMap$1(handleEnds[1], viewExtend, percentExtent, true)\n        ]);\n\n        return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (nonRealtime) {\n        var displaybles = this._displayables;\n        var handleEnds = this._handleEnds;\n        var handleInterval = asc$2(handleEnds.slice());\n        var size = this._size;\n\n        each$23([0, 1], function (handleIndex) {\n            // Handles\n            var handle = displaybles.handles[handleIndex];\n            var handleHeight = this._handleHeight;\n            handle.attr({\n                scale: [handleHeight / 2, handleHeight / 2],\n                position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2]\n            });\n        }, this);\n\n        // Filler\n        displaybles.filler.setShape({\n            x: handleInterval[0],\n            y: 0,\n            width: handleInterval[1] - handleInterval[0],\n            height: size[1]\n        });\n\n        this._updateDataInfo(nonRealtime);\n    },\n\n    /**\n     * @private\n     */\n    _updateDataInfo: function (nonRealtime) {\n        var dataZoomModel = this.dataZoomModel;\n        var displaybles = this._displayables;\n        var handleLabels = displaybles.handleLabels;\n        var orient = this._orient;\n        var labelTexts = ['', ''];\n\n        // FIXME\n        // date型，支持formatter，autoformatter（ec2 date.getAutoFormatter）\n        if (dataZoomModel.get('showDetail')) {\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n\n            if (axisProxy) {\n                var axis = axisProxy.getAxisModel().axis;\n                var range = this._range;\n\n                var dataInterval = nonRealtime\n                    // See #4434, data and axis are not processed and reset yet in non-realtime mode.\n                    ? axisProxy.calculateDataWindow({\n                        start: range[0], end: range[1]\n                    }).valueWindow\n                    : axisProxy.getDataValueWindow();\n\n                labelTexts = [\n                    this._formatLabel(dataInterval[0], axis),\n                    this._formatLabel(dataInterval[1], axis)\n                ];\n            }\n        }\n\n        var orderedHandleEnds = asc$2(this._handleEnds.slice());\n\n        setLabel.call(this, 0);\n        setLabel.call(this, 1);\n\n        function setLabel(handleIndex) {\n            // Label\n            // Text should not transform by barGroup.\n            // Ignore handlers transform\n            var barTransform = getTransform(\n                displaybles.handles[handleIndex].parent, this.group\n            );\n            var direction = transformDirection(\n                handleIndex === 0 ? 'right' : 'left', barTransform\n            );\n            var offset = this._handleWidth / 2 + LABEL_GAP;\n            var textPoint = applyTransform$1(\n                [\n                    orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),\n                    this._size[1] / 2\n                ],\n                barTransform\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,\n                textAlign: orient === HORIZONTAL ? direction : 'center',\n                text: labelTexts[handleIndex]\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _formatLabel: function (value, axis) {\n        var dataZoomModel = this.dataZoomModel;\n        var labelFormatter = dataZoomModel.get('labelFormatter');\n\n        var labelPrecision = dataZoomModel.get('labelPrecision');\n        if (labelPrecision == null || labelPrecision === 'auto') {\n            labelPrecision = axis.getPixelPrecision();\n        }\n\n        var valueStr = (value == null || isNaN(value))\n            ? ''\n            // FIXME Glue code\n            : (axis.type === 'category' || axis.type === 'time')\n                ? axis.scale.getLabel(Math.round(value))\n                // param of toFixed should less then 20.\n                : value.toFixed(Math.min(labelPrecision, 20));\n\n        return isFunction$1(labelFormatter)\n            ? labelFormatter(value, valueStr)\n            : isString(labelFormatter)\n            ? labelFormatter.replace('{value}', valueStr)\n            : valueStr;\n    },\n\n    /**\n     * @private\n     * @param {boolean} showOrHide true: show, false: hide\n     */\n    _showDataInfo: function (showOrHide) {\n        // Always show when drgging.\n        showOrHide = this._dragging || showOrHide;\n\n        var handleLabels = this._displayables.handleLabels;\n        handleLabels[0].attr('invisible', !showOrHide);\n        handleLabels[1].attr('invisible', !showOrHide);\n    },\n\n    _onDragMove: function (handleIndex, dx, dy) {\n        this._dragging = true;\n\n        // Transform dx, dy to bar coordination.\n        var barTransform = this._displayables.barGroup.getLocalTransform();\n        var vertex = applyTransform$1([dx, dy], barTransform, true);\n\n        var changed = this._updateInterval(handleIndex, vertex[0]);\n\n        var realtime = this.dataZoomModel.get('realtime');\n\n        this._updateView(!realtime);\n\n        // Avoid dispatch dataZoom repeatly but range not changed,\n        // which cause bad visual effect when progressive enabled.\n        changed && realtime && this._dispatchZoomAction();\n    },\n\n    _onDragEnd: function () {\n        this._dragging = false;\n        this._showDataInfo(false);\n\n        // While in realtime mode and stream mode, dispatch action when\n        // drag end will cause the whole view rerender, which is unnecessary.\n        var realtime = this.dataZoomModel.get('realtime');\n        !realtime && this._dispatchZoomAction();\n    },\n\n    _onClickPanelClick: function (e) {\n        var size = this._size;\n        var localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        if (localPoint[0] < 0 || localPoint[0] > size[0]\n            || localPoint[1] < 0 || localPoint[1] > size[1]\n        ) {\n            return;\n        }\n\n        var handleEnds = this._handleEnds;\n        var center = (handleEnds[0] + handleEnds[1]) / 2;\n\n        var changed = this._updateInterval('all', localPoint[0] - center);\n        this._updateView();\n        changed && this._dispatchZoomAction();\n    },\n\n    /**\n     * This action will be throttled.\n     * @private\n     */\n    _dispatchZoomAction: function () {\n        var range = this._range;\n\n        this.api.dispatchAction({\n            type: 'dataZoom',\n            from: this.uid,\n            dataZoomId: this.dataZoomModel.id,\n            start: range[0],\n            end: range[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _findCoordRect: function () {\n        // Find the grid coresponding to the first axis referred by dataZoom.\n        var rect;\n        each$23(this.getTargetCoordInfo(), function (coordInfoList) {\n            if (!rect && coordInfoList.length) {\n                var coordSys = coordInfoList[0].model.coordinateSystem;\n                rect = coordSys.getRect && coordSys.getRect();\n            }\n        });\n        if (!rect) {\n            var width = this.api.getWidth();\n            var height = this.api.getHeight();\n            rect = {\n                x: width * 0.2,\n                y: height * 0.2,\n                width: width * 0.6,\n                height: height * 0.6\n            };\n        }\n\n        return rect;\n    }\n\n});\n\nfunction getOtherDim(thisDim) {\n    // FIXME\n    // 这个逻辑和getOtherAxis里一致，但是写在这里是否不好\n    var map$$1 = {x: 'y', y: 'x', radius: 'angle', angle: 'radius'};\n    return map$$1[thisDim];\n}\n\nfunction getCursor(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        disabled: false,   // Whether disable this inside zoom.\n        zoomLock: false,   // Whether disable zoom but only pan.\n        zoomOnMouseWheel: true, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseMove: true,   // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseWheel: false, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        preventDefaultMouseMove: true\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Only create one roam controller for each coordinate system.\n// one roam controller might be refered by two inside data zoom\n// components (for example, one for x and one for y). When user\n// pan or zoom, only dispatch one action for those data zoom\n// components.\n\nvar ATTR$1 = '\\0_ec_dataZoom_roams';\n\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} dataZoomInfo\n * @param {string} dataZoomInfo.coordId\n * @param {Function} dataZoomInfo.containsPoint\n * @param {Array.<string>} dataZoomInfo.allCoordIds\n * @param {string} dataZoomInfo.dataZoomId\n * @param {Object} dataZoomInfo.getRange\n * @param {Function} dataZoomInfo.getRange.pan\n * @param {Function} dataZoomInfo.getRange.zoom\n * @param {Function} dataZoomInfo.getRange.scrollMove\n * @param {boolean} dataZoomInfo.dataZoomModel\n */\nfunction register$2(api, dataZoomInfo) {\n    var store = giveStore(api);\n    var theDataZoomId = dataZoomInfo.dataZoomId;\n    var theCoordId = dataZoomInfo.coordId;\n\n    // Do clean when a dataZoom changes its target coordnate system.\n    // Avoid memory leak, dispose all not-used-registered.\n    each$1(store, function (record, coordId) {\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[theDataZoomId]\n            && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0\n        ) {\n            delete dataZoomInfos[theDataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n\n    var record = store[theCoordId];\n    // Create if needed.\n    if (!record) {\n        record = store[theCoordId] = {\n            coordId: theCoordId,\n            dataZoomInfos: {},\n            count: 0\n        };\n        record.controller = createController(api, record);\n        record.dispatchAction = curry(dispatchAction$1, api);\n    }\n\n    // Update reference of dataZoom.\n    !(record.dataZoomInfos[theDataZoomId]) && record.count++;\n    record.dataZoomInfos[theDataZoomId] = dataZoomInfo;\n\n    var controllerParams = mergeControllerParams(record.dataZoomInfos);\n    record.controller.enable(controllerParams.controlType, controllerParams.opt);\n\n    // Consider resize, area should be always updated.\n    record.controller.setPointerChecker(dataZoomInfo.containsPoint);\n\n    // Update throttle.\n    createOrUpdate(\n        record,\n        'dispatchAction',\n        dataZoomInfo.dataZoomModel.get('throttle', true),\n        'fixRate'\n    );\n}\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {string} dataZoomId\n */\nfunction unregister$1(api, dataZoomId) {\n    var store = giveStore(api);\n\n    each$1(store, function (record) {\n        record.controller.dispose();\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[dataZoomId]) {\n            delete dataZoomInfos[dataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n}\n\n/**\n * @public\n */\nfunction generateCoordId(coordModel) {\n    return coordModel.type + '\\0_' + coordModel.id;\n}\n\n/**\n * Key: coordId, value: {dataZoomInfos: [], count, controller}\n * @type {Array.<Object>}\n */\nfunction giveStore(api) {\n    // Mount store on zrender instance, so that we do not\n    // need to worry about dispose.\n    var zr = api.getZr();\n    return zr[ATTR$1] || (zr[ATTR$1] = {});\n}\n\nfunction createController(api, newRecord) {\n    var controller = new RoamController(api.getZr());\n\n    each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n        controller.on(eventName, function (event) {\n            var batch = [];\n\n            each$1(newRecord.dataZoomInfos, function (info) {\n                // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove,\n                // moveOnMouseWheel, ...) enabled.\n                if (!event.isAvailableBehavior(info.dataZoomModel.option)) {\n                    return;\n                }\n\n                var method = (info.getRange || {})[eventName];\n                var range = method && method(newRecord.controller, event);\n\n                !info.dataZoomModel.get('disabled', true) && range && batch.push({\n                    dataZoomId: info.dataZoomId,\n                    start: range[0],\n                    end: range[1]\n                });\n            });\n\n            batch.length && newRecord.dispatchAction(batch);\n        });\n    });\n\n    return controller;\n}\n\nfunction cleanStore(store) {\n    each$1(store, function (record, coordId) {\n        if (!record.count) {\n            record.controller.dispose();\n            delete store[coordId];\n        }\n    });\n}\n\n/**\n * This action will be throttled.\n */\nfunction dispatchAction$1(api, batch) {\n    api.dispatchAction({\n        type: 'dataZoom',\n        batch: batch\n    });\n}\n\n/**\n * Merge roamController settings when multiple dataZooms share one roamController.\n */\nfunction mergeControllerParams(dataZoomInfos) {\n    var controlType;\n    // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated\n    // as string, it is probably revert to reserved word by compress tool. See #7411.\n    var prefix = 'type_';\n    var typePriority = {\n        'type_true': 2,\n        'type_move': 1,\n        'type_false': 0,\n        'type_undefined': -1\n    };\n    var preventDefaultMouseMove = true;\n\n    each$1(dataZoomInfos, function (dataZoomInfo) {\n        var dataZoomModel = dataZoomInfo.dataZoomModel;\n        var oneType = dataZoomModel.get('disabled', true)\n            ? false\n            : dataZoomModel.get('zoomLock', true)\n            ? 'move'\n            : true;\n        if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) {\n            controlType = oneType;\n        }\n\n        // Prevent default move event by default. If one false, do not prevent. Otherwise\n        // users may be confused why it does not work when multiple insideZooms exist.\n        preventDefaultMouseMove &= dataZoomModel.get('preventDefaultMouseMove', true);\n    });\n\n    return {\n        controlType: controlType,\n        opt: {\n            // RoamController will enable all of these functionalities,\n            // and the final behavior is determined by its event listener\n            // provided by each inside zoom.\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            moveOnMouseWheel: true,\n            preventDefaultMouseMove: !!preventDefaultMouseMove\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$5 = bind;\n\nvar InsideZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        /**\n         * 'throttle' is used in this.dispatchAction, so we save range\n         * to avoid missing some 'pan' info.\n         * @private\n         * @type {Array.<number>}\n         */\n        this._range;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        InsideZoomView.superApply(this, 'render', arguments);\n\n        // Hance the `throttle` util ensures to preserve command order,\n        // here simply updating range all the time will not cause missing\n        // any of the the roam change.\n        this._range = dataZoomModel.getPercentRange();\n\n        // Reset controllers.\n        each$1(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {\n\n            var allCoordIds = map(coordInfoList, function (coordInfo) {\n                return generateCoordId(coordInfo.model);\n            });\n\n            each$1(coordInfoList, function (coordInfo) {\n                var coordModel = coordInfo.model;\n\n                var getRange = {};\n                each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n                    getRange[eventName] = bind$5(roamHandlers[eventName], this, coordInfo, coordSysName);\n                }, this);\n\n                register$2(\n                    api,\n                    {\n                        coordId: generateCoordId(coordModel),\n                        allCoordIds: allCoordIds,\n                        containsPoint: function (e, x, y) {\n                            return coordModel.coordinateSystem.containPoint([x, y]);\n                        },\n                        dataZoomId: dataZoomModel.id,\n                        dataZoomModel: dataZoomModel,\n                        getRange: getRange\n                    }\n                );\n            }, this);\n\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        unregister$1(this.api, this.dataZoomModel.id);\n        InsideZoomView.superApply(this, 'dispose', arguments);\n        this._range = null;\n    }\n\n});\n\nvar roamHandlers = {\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    zoom: function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var directionInfo = getDirectionInfo[coordSysName](\n            null, [e.originX, e.originY], axisModel, controller, coordInfo\n        );\n        var percentPoint = (\n            directionInfo.signal > 0\n                ? (directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel)\n                : (directionInfo.pixel - directionInfo.pixelStart)\n            ) / directionInfo.pixelLength * (range[1] - range[0]) + range[0];\n\n        var scale = Math.max(1 / e.scale, 0);\n        range[0] = (range[0] - percentPoint) * scale + percentPoint;\n        range[1] = (range[1] - percentPoint) * scale + percentPoint;\n\n        // Restrict range.\n        var minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n\n        sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    },\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo\n        );\n\n        return directionInfo.signal\n            * (range[1] - range[0])\n            * directionInfo.pixel / directionInfo.pixelLength;\n    }),\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    scrollMove: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo\n        );\n        return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta;\n    })\n};\n\nfunction makeMover(getPercentDelta) {\n    return function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var percentDelta = getPercentDelta(\n            range, axisModel, coordInfo, coordSysName, controller, e\n        );\n\n        sliderMove(percentDelta, range, [0, 100], 'all');\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    };\n}\n\nvar getDirectionInfo = {\n\n    grid: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.dim === 'x') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // axis.dim === 'y'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    polar: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var polar = coordInfo.model.coordinateSystem;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n        var angleExtent = polar.getAngleAxis().getExtent();\n\n        oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0];\n        newPoint = polar.pointToCoord(newPoint);\n\n        if (axisModel.mainType === 'radiusAxis') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]);\n            // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]);\n            ret.pixelLength = radiusExtent[1] - radiusExtent[0];\n            ret.pixelStart = radiusExtent[0];\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'angleAxis'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]);\n            // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]);\n            ret.pixelLength = angleExtent[1] - angleExtent[0];\n            ret.pixelStart = angleExtent[0];\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    singleAxis: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        var ret = {};\n\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.orient === 'horizontal') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'vertical'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor({\n\n    // `dataZoomProcessor` will only be performed in needed series. Consider if\n    // there is a line series and a pie series, it is better not to update the\n    // line series if only pie series is needed to be updated.\n    getTargetSeries: function (ecModel) {\n        var seriesModelMap = createHashMap();\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                var axisProxy = dataZoomModel.getAxisProxy(dimNames.name, axisIndex);\n                each$1(axisProxy.getTargetSeriesModels(), function (seriesModel) {\n                    seriesModelMap.set(seriesModel.uid, seriesModel);\n                });\n            });\n        });\n\n        return seriesModelMap;\n    },\n\n    modifyOutputEnd: true,\n\n    // Consider appendData, where filter should be performed. Because data process is\n    // in block mode currently, it is not need to worry about that the overallProgress\n    // execute every frame.\n    overallReset: function (ecModel, api) {\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // We calculate window and reset axis here but not in model\n            // init stage and not after action dispatch handler, because\n            // reset should be called after seriesData.restoreData.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel, api);\n            });\n\n            // Caution: data zoom filtering is order sensitive when using\n            // percent range and no min/max/scale set on axis.\n            // For example, we have dataZoom definition:\n            // [\n            //      {xAxisIndex: 0, start: 30, end: 70},\n            //      {yAxisIndex: 0, start: 20, end: 80}\n            // ]\n            // In this case, [20, 80] of y-dataZoom should be based on data\n            // that have filtered by x-dataZoom using range of [30, 70],\n            // but should not be based on full raw data. Thus sliding\n            // x-dataZoom will change both ranges of xAxis and yAxis,\n            // while sliding y-dataZoom will only change the range of yAxis.\n            // So we should filter x-axis after reset x-axis immediately,\n            // and then reset y-axis and filter y-axis.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel, api);\n            });\n        });\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // Fullfill all of the range props so that user\n            // is able to get them from chart.getOption().\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n            var percentRange = axisProxy.getDataPercentWindow();\n            var valueRange = axisProxy.getDataValueWindow();\n\n            dataZoomModel.setRawRange({\n                start: percentRange[0],\n                end: percentRange[1],\n                startValue: valueRange[0],\n                endValue: valueRange[1]\n            }, true);\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction('dataZoom', function (payload, ecModel) {\n\n    var linkedNodesFinder = createLinkedNodesFinder(\n        bind(ecModel.eachComponent, ecModel, 'dataZoom'),\n        eachAxisDim$1,\n        function (model, dimNames) {\n            return model.get(dimNames.axisIndex);\n        }\n    );\n\n    var effectedModels = [];\n\n    ecModel.eachComponent(\n        {mainType: 'dataZoom', query: payload},\n        function (model, index) {\n            effectedModels.push.apply(\n                effectedModels, linkedNodesFinder(model).nodes\n            );\n        }\n    );\n\n    each$1(effectedModels, function (dataZoomModel, index) {\n        dataZoomModel.setRawRange({\n            start: payload.start,\n            end: payload.end,\n            startValue: payload.startValue,\n            endValue: payload.endValue\n        });\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$24 = each$1;\n\nvar preprocessor$2 = function (option) {\n    var visualMap = option && option.visualMap;\n\n    if (!isArray(visualMap)) {\n        visualMap = visualMap ? [visualMap] : [];\n    }\n\n    each$24(visualMap, function (opt) {\n        if (!opt) {\n            return;\n        }\n\n        // rename splitList to pieces\n        if (has$1(opt, 'splitList') && !has$1(opt, 'pieces')) {\n            opt.pieces = opt.splitList;\n            delete opt.splitList;\n        }\n\n        var pieces = opt.pieces;\n        if (pieces && isArray(pieces)) {\n            each$24(pieces, function (piece) {\n                if (isObject$1(piece)) {\n                    if (has$1(piece, 'start') && !has$1(piece, 'min')) {\n                        piece.min = piece.start;\n                    }\n                    if (has$1(piece, 'end') && !has$1(piece, 'max')) {\n                        piece.max = piece.end;\n                    }\n                }\n            });\n        }\n    });\n};\n\nfunction has$1(obj, name) {\n    return obj && obj.hasOwnProperty && obj.hasOwnProperty(name);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('visualMap', function (option) {\n    // Compatible with ec2, when splitNumber === 0, continuous visualMap will be used.\n    return (\n            !option.categories\n            && (\n                !(\n                    option.pieces\n                        ? option.pieces.length > 0\n                        : option.splitNumber > 0\n                )\n                || option.calculable\n            )\n        )\n        ? 'continuous' : 'piecewise';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar VISUAL_PRIORITY = PRIORITY.VISUAL.COMPONENT;\n\nregisterVisual(VISUAL_PRIORITY, {\n    createOnAllSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var resetDefines = [];\n        ecModel.eachComponent('visualMap', function (visualMapModel) {\n            var pipelineContext = seriesModel.pipelineContext;\n            if (!visualMapModel.isTargetSeries(seriesModel)\n                || (pipelineContext && pipelineContext.large)\n            ) {\n                return;\n            }\n\n            resetDefines.push(incrementalApplyVisual(\n                visualMapModel.stateList,\n                visualMapModel.targetVisuals,\n                bind(visualMapModel.getValueState, visualMapModel),\n                visualMapModel.getDataDimension(seriesModel.getData())\n            ));\n        });\n\n        return resetDefines;\n    }\n});\n\n// Only support color.\nregisterVisual(VISUAL_PRIORITY, {\n    createOnAllSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var visualMetaList = [];\n\n        ecModel.eachComponent('visualMap', function (visualMapModel) {\n            if (visualMapModel.isTargetSeries(seriesModel)) {\n                var visualMeta = visualMapModel.getVisualMeta(\n                    bind(getColorVisual, null, seriesModel, visualMapModel)\n                ) || {stops: [], outerColors: []};\n\n                var concreteDim = visualMapModel.getDataDimension(data);\n                var dimInfo = data.getDimensionInfo(concreteDim);\n                if (dimInfo != null) {\n                    // visualMeta.dimension should be dimension index, but not concrete dimension.\n                    visualMeta.dimension = dimInfo.index;\n                    visualMetaList.push(visualMeta);\n                }\n            }\n        });\n\n        // console.log(JSON.stringify(visualMetaList.map(a => a.stops)));\n        seriesModel.getData().setVisual('visualMeta', visualMetaList);\n    }\n});\n\n// FIXME\n// performance and export for heatmap?\n// value can be Infinity or -Infinity\nfunction getColorVisual(seriesModel, visualMapModel, value, valueState) {\n    var mappings = visualMapModel.targetVisuals[valueState];\n    var visualTypes = VisualMapping.prepareVisualTypes(mappings);\n    var resultVisual = {\n        color: seriesModel.getData().getVisual('color') // default color.\n    };\n\n    for (var i = 0, len = visualTypes.length; i < len; i++) {\n        var type = visualTypes[i];\n        var mapping = mappings[\n            type === 'opacity' ? '__alphaForOpacity' : type\n        ];\n        mapping && mapping.applyVisual(value, getVisual, setVisual);\n    }\n\n    return resultVisual.color;\n\n    function getVisual(key) {\n        return resultVisual[key];\n    }\n\n    function setVisual(key, value) {\n        resultVisual[key] = value;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual mapping.\n */\n\nvar visualDefault = {\n\n    /**\n     * @public\n     */\n    get: function (visualType, key, isCategory) {\n        var value = clone(\n            (defaultOption$3[visualType] || {})[key]\n        );\n\n        return isCategory\n            ? (isArray(value) ? value[value.length - 1] : value)\n            : value;\n    }\n\n};\n\nvar defaultOption$3 = {\n\n    color: {\n        active: ['#006edd', '#e0ffff'],\n        inactive: ['rgba(0,0,0,0)']\n    },\n\n    colorHue: {\n        active: [0, 360],\n        inactive: [0, 0]\n    },\n\n    colorSaturation: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    colorLightness: {\n        active: [0.9, 0.5],\n        inactive: [0, 0]\n    },\n\n    colorAlpha: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    opacity: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    symbol: {\n        active: ['circle', 'roundRect', 'diamond'],\n        inactive: ['none']\n    },\n\n    symbolSize: {\n        active: [10, 50],\n        inactive: [0, 0]\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar mapVisual$2 = VisualMapping.mapVisual;\nvar eachVisual = VisualMapping.eachVisual;\nvar isArray$3 = isArray;\nvar each$25 = each$1;\nvar asc$3 = asc;\nvar linearMap$2 = linearMap;\nvar noop$2 = noop;\n\nvar VisualMapModel = extendComponentModel({\n\n    type: 'visualMap',\n\n    dependencies: ['series'],\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    stateList: ['inRange', 'outOfRange'],\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    replacableOptionKeys: [\n        'inRange', 'outOfRange', 'target', 'controller', 'color'\n    ],\n\n    /**\n     * [lowerBound, upperBound]\n     *\n     * @readOnly\n     * @type {Array.<number>}\n     */\n    dataBound: [-Infinity, Infinity],\n\n    /**\n     * @readOnly\n     * @type {string|Object}\n     */\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        zlevel: 0,\n        z: 4,\n\n        seriesIndex: 'all',     // 'all' or null/undefined: all series.\n                                // A number or an array of number: the specified series.\n\n                                // set min: 0, max: 200, only for campatible with ec2.\n                                // In fact min max should not have default value.\n        min: 0,                 // min value, must specified if pieces is not specified.\n        max: 200,               // max value, must specified if pieces is not specified.\n\n        dimension: null,\n        inRange: null,          // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',\n                                // 'symbol', 'symbolSize'\n        outOfRange: null,       // 'color', 'colorHue', 'colorSaturation',\n                                // 'colorLightness', 'colorAlpha',\n                                // 'symbol', 'symbolSize'\n\n        left: 0,                // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)\n        right: null,            // The same as left.\n        top: null,              // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)\n        bottom: 0,              // The same as top.\n\n        itemWidth: null,\n        itemHeight: null,\n        inverse: false,\n        orient: 'vertical',        // 'horizontal' ¦ 'vertical'\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderColor: '#ccc',       // 值域边框颜色\n        contentColor: '#5793f3',\n        inactiveColor: '#aaa',\n        borderWidth: 0,            // 值域边框线宽，单位px，默认为0（无边框）\n        padding: 5,                // 值域内边距，单位px，默认各方向内边距为5，\n                                    // 接受数组分别设定上右下左边距，同css\n        textGap: 10,               //\n        precision: 0,              // 小数精度，默认为0，无小数点\n        color: null,               //颜色（deprecated，兼容ec2，顺序同pieces，不同于inRange/outOfRange）\n\n        formatter: null,\n        text: null,                // 文本，如['高', '低']，兼容ec2，text[0]对应高值，text[1]对应低值\n        textStyle: {\n            color: '#333'          // 值域文字颜色\n        }\n    },\n\n    /**\n     * @protected\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * @private\n         * @type {Array.<number>}\n         */\n        this._dataExtent;\n\n        /**\n         * @readOnly\n         */\n        this.targetVisuals = {};\n\n        /**\n         * @readOnly\n         */\n        this.controllerVisuals = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * [width, height]\n         * @readOnly\n         * @type {Array.<number>}\n         */\n        this.itemSize;\n\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    /**\n     * @protected\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n\n        // FIXME\n        // necessary?\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        !isInit && replaceVisualOption(\n            thisOption, newOption, this.replacableOptionKeys\n        );\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this.resetItemSize();\n\n        this.completeVisualOption();\n    },\n\n    /**\n     * @protected\n     */\n    resetVisual: function (supplementVisualOption) {\n        var stateList = this.stateList;\n        supplementVisualOption = bind(supplementVisualOption, this);\n\n        this.controllerVisuals = createVisualMappings(\n            this.option.controller, stateList, supplementVisualOption\n        );\n        this.targetVisuals = createVisualMappings(\n            this.option.target, stateList, supplementVisualOption\n        );\n    },\n\n    /**\n     * @protected\n     * @return {Array.<number>} An array of series indices.\n     */\n    getTargetSeriesIndices: function () {\n        var optionSeriesIndex = this.option.seriesIndex;\n        var seriesIndices = [];\n\n        if (optionSeriesIndex == null || optionSeriesIndex === 'all') {\n            this.ecModel.eachSeries(function (seriesModel, index) {\n                seriesIndices.push(index);\n            });\n        }\n        else {\n            seriesIndices = normalizeToArray(optionSeriesIndex);\n        }\n\n        return seriesIndices;\n    },\n\n    /**\n     * @public\n     */\n    eachTargetSeries: function (callback, context) {\n        each$1(this.getTargetSeriesIndices(), function (seriesIndex) {\n            callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex));\n        }, this);\n    },\n\n    /**\n     * @pubilc\n     */\n    isTargetSeries: function (seriesModel) {\n        var is = false;\n        this.eachTargetSeries(function (model) {\n            model === seriesModel && (is = true);\n        });\n        return is;\n    },\n\n    /**\n     * @example\n     * this.formatValueText(someVal); // format single numeric value to text.\n     * this.formatValueText(someVal, true); // format single category value to text.\n     * this.formatValueText([min, max]); // format numeric min-max to text.\n     * this.formatValueText([this.dataBound[0], max]); // using data lower bound.\n     * this.formatValueText([min, this.dataBound[1]]); // using data upper bound.\n     *\n     * @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].\n     * @param {boolean} [isCategory=false] Only available when value is number.\n     * @param {Array.<string>} edgeSymbols Open-close symbol when value is interval.\n     * @return {string}\n     * @protected\n     */\n    formatValueText: function (value, isCategory, edgeSymbols) {\n        var option = this.option;\n        var precision = option.precision;\n        var dataBound = this.dataBound;\n        var formatter = option.formatter;\n        var isMinMax;\n        var textValue;\n        edgeSymbols = edgeSymbols || ['<', '>'];\n\n        if (isArray(value)) {\n            value = value.slice();\n            isMinMax = true;\n        }\n\n        textValue = isCategory\n            ? value\n            : (isMinMax\n                ? [toFixed(value[0]), toFixed(value[1])]\n                : toFixed(value)\n            );\n\n        if (isString(formatter)) {\n            return formatter\n                .replace('{value}', isMinMax ? textValue[0] : textValue)\n                .replace('{value2}', isMinMax ? textValue[1] : textValue);\n        }\n        else if (isFunction$1(formatter)) {\n            return isMinMax\n                ? formatter(value[0], value[1])\n                : formatter(value);\n        }\n\n        if (isMinMax) {\n            if (value[0] === dataBound[0]) {\n                return edgeSymbols[0] + ' ' + textValue[1];\n            }\n            else if (value[1] === dataBound[1]) {\n                return edgeSymbols[1] + ' ' + textValue[0];\n            }\n            else {\n                return textValue[0] + ' - ' + textValue[1];\n            }\n        }\n        else { // Format single value (includes category case).\n            return textValue;\n        }\n\n        function toFixed(val) {\n            return val === dataBound[0]\n                ? 'min'\n                : val === dataBound[1]\n                ? 'max'\n                : (+val).toFixed(Math.min(precision, 20));\n        }\n    },\n\n    /**\n     * @protected\n     */\n    resetExtent: function () {\n        var thisOption = this.option;\n\n        // Can not calculate data extent by data here.\n        // Because series and data may be modified in processing stage.\n        // So we do not support the feature \"auto min/max\".\n\n        var extent = asc$3([thisOption.min, thisOption.max]);\n\n        this._dataExtent = extent;\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/data/List} list\n     * @return {string} Concrete dimention. If return null/undefined,\n     *                  no dimension used.\n     */\n    getDataDimension: function (list) {\n        var optDim = this.option.dimension;\n        var listDimensions = list.dimensions;\n        if (optDim == null && !listDimensions.length) {\n            return;\n        }\n\n        if (optDim != null) {\n            return list.getDimension(optDim);\n        }\n\n        var dimNames = list.dimensions;\n        for (var i = dimNames.length - 1; i >= 0; i--) {\n            var dimName = dimNames[i];\n            var dimInfo = list.getDimensionInfo(dimName);\n            if (!dimInfo.isCalculationCoord) {\n                return dimName;\n            }\n        }\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    getExtent: function () {\n        return this._dataExtent.slice();\n    },\n\n    /**\n     * @protected\n     */\n    completeVisualOption: function () {\n        var ecModel = this.ecModel;\n        var thisOption = this.option;\n        var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange};\n\n        var target = thisOption.target || (thisOption.target = {});\n        var controller = thisOption.controller || (thisOption.controller = {});\n\n        merge(target, base); // Do not override\n        merge(controller, base); // Do not override\n\n        var isCategory = this.isCategory();\n\n        completeSingle.call(this, target);\n        completeSingle.call(this, controller);\n        completeInactive.call(this, target, 'inRange', 'outOfRange');\n        // completeInactive.call(this, target, 'outOfRange', 'inRange');\n        completeController.call(this, controller);\n\n        function completeSingle(base) {\n            // Compatible with ec2 dataRange.color.\n            // The mapping order of dataRange.color is: [high value, ..., low value]\n            // whereas inRange.color and outOfRange.color is [low value, ..., high value]\n            // Notice: ec2 has no inverse.\n            if (isArray$3(thisOption.color)\n                // If there has been inRange: {symbol: ...}, adding color is a mistake.\n                // So adding color only when no inRange defined.\n                && !base.inRange\n            ) {\n                base.inRange = {color: thisOption.color.slice().reverse()};\n            }\n\n            // Compatible with previous logic, always give a defautl color, otherwise\n            // simple config with no inRange and outOfRange will not work.\n            // Originally we use visualMap.color as the default color, but setOption at\n            // the second time the default color will be erased. So we change to use\n            // constant DEFAULT_COLOR.\n            // If user do not want the defualt color, set inRange: {color: null}.\n            base.inRange = base.inRange || {color: ecModel.get('gradientColor')};\n\n            // If using shortcut like: {inRange: 'symbol'}, complete default value.\n            each$25(this.stateList, function (state) {\n                var visualType = base[state];\n\n                if (isString(visualType)) {\n                    var defa = visualDefault.get(visualType, 'active', isCategory);\n                    if (defa) {\n                        base[state] = {};\n                        base[state][visualType] = defa;\n                    }\n                    else {\n                        // Mark as not specified.\n                        delete base[state];\n                    }\n                }\n            }, this);\n        }\n\n        function completeInactive(base, stateExist, stateAbsent) {\n            var optExist = base[stateExist];\n            var optAbsent = base[stateAbsent];\n\n            if (optExist && !optAbsent) {\n                optAbsent = base[stateAbsent] = {};\n                each$25(optExist, function (visualData, visualType) {\n                    if (!VisualMapping.isValidType(visualType)) {\n                        return;\n                    }\n\n                    var defa = visualDefault.get(visualType, 'inactive', isCategory);\n\n                    if (defa != null) {\n                        optAbsent[visualType] = defa;\n\n                        // Compatibable with ec2:\n                        // Only inactive color to rgba(0,0,0,0) can not\n                        // make label transparent, so use opacity also.\n                        if (visualType === 'color'\n                            && !optAbsent.hasOwnProperty('opacity')\n                            && !optAbsent.hasOwnProperty('colorAlpha')\n                        ) {\n                            optAbsent.opacity = [0, 0];\n                        }\n                    }\n                });\n            }\n        }\n\n        function completeController(controller) {\n            var symbolExists = (controller.inRange || {}).symbol\n                || (controller.outOfRange || {}).symbol;\n            var symbolSizeExists = (controller.inRange || {}).symbolSize\n                || (controller.outOfRange || {}).symbolSize;\n            var inactiveColor = this.get('inactiveColor');\n\n            each$25(this.stateList, function (state) {\n\n                var itemSize = this.itemSize;\n                var visuals = controller[state];\n\n                // Set inactive color for controller if no other color\n                // attr (like colorAlpha) specified.\n                if (!visuals) {\n                    visuals = controller[state] = {\n                        color: isCategory ? inactiveColor : [inactiveColor]\n                    };\n                }\n\n                // Consistent symbol and symbolSize if not specified.\n                if (visuals.symbol == null) {\n                    visuals.symbol = symbolExists\n                        && clone(symbolExists)\n                        || (isCategory ? 'roundRect' : ['roundRect']);\n                }\n                if (visuals.symbolSize == null) {\n                    visuals.symbolSize = symbolSizeExists\n                        && clone(symbolSizeExists)\n                        || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);\n                }\n\n                // Filter square and none.\n                visuals.symbol = mapVisual$2(visuals.symbol, function (symbol) {\n                    return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol;\n                });\n\n                // Normalize symbolSize\n                var symbolSize = visuals.symbolSize;\n\n                if (symbolSize != null) {\n                    var max = -Infinity;\n                    // symbolSize can be object when categories defined.\n                    eachVisual(symbolSize, function (value) {\n                        value > max && (max = value);\n                    });\n                    visuals.symbolSize = mapVisual$2(symbolSize, function (value) {\n                        return linearMap$2(value, [0, max], [0, itemSize[0]], true);\n                    });\n                }\n\n            }, this);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    resetItemSize: function () {\n        this.itemSize = [\n            parseFloat(this.get('itemWidth')),\n            parseFloat(this.get('itemHeight'))\n        ];\n    },\n\n    /**\n     * @public\n     */\n    isCategory: function () {\n        return !!this.option.categories;\n    },\n\n    /**\n     * @public\n     * @abstract\n     */\n    setSelected: noop$2,\n\n    /**\n     * @public\n     * @abstract\n     * @param {*|module:echarts/data/List} valueOrData\n     * @param {number} dataIndex\n     * @return {string} state See this.stateList\n     */\n    getValueState: noop$2,\n\n    /**\n     * FIXME\n     * Do not publish to thirt-part-dev temporarily\n     * util the interface is stable. (Should it return\n     * a function but not visual meta?)\n     *\n     * @pubilc\n     * @abstract\n     * @param {Function} getColorVisual\n     *        params: value, valueState\n     *        return: color\n     * @return {Object} visualMeta\n     *        should includes {stops, outerColors}\n     *        outerColor means [colorBeyondMinValue, colorBeyondMaxValue]\n     */\n    getVisualMeta: noop$2\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Constant\nvar DEFAULT_BAR_BOUND = [20, 140];\n\nvar ContinuousModel = VisualMapModel.extend({\n\n    type: 'visualMap.continuous',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        align: 'auto',           // 'auto', 'left', 'right', 'top', 'bottom'\n        calculable: false,       // This prop effect default component type determine,\n                                 // See echarts/component/visualMap/typeDefaulter.\n        range: null,             // selected range. In default case `range` is [min, max]\n                                 // and can auto change along with modification of min max,\n                                 // util use specifid a range.\n        realtime: true,          // Whether realtime update.\n        itemHeight: null,        // The length of the range control edge.\n        itemWidth: null,         // The length of the other side.\n        hoverLink: true,         // Enable hover highlight.\n        hoverLinkDataSize: null, // The size of hovered data.\n        hoverLinkOnHandle: null  // Whether trigger hoverLink when hover handle.\n                                 // If not specified, follow the value of `realtime`.\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        ContinuousModel.superApply(this, 'optionUpdated', arguments);\n\n        this.resetExtent();\n\n        this.resetVisual(function (mappingOption) {\n            mappingOption.mappingMethod = 'linear';\n            mappingOption.dataExtent = this.getExtent();\n        });\n\n        this._resetRange();\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    resetItemSize: function () {\n        ContinuousModel.superApply(this, 'resetItemSize', arguments);\n\n        var itemSize = this.itemSize;\n\n        this._orient === 'horizontal' && itemSize.reverse();\n\n        (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]);\n        (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]);\n    },\n\n    /**\n     * @private\n     */\n    _resetRange: function () {\n        var dataExtent = this.getExtent();\n        var range = this.option.range;\n\n        if (!range || range.auto) {\n            // `range` should always be array (so we dont use other\n            // value like 'auto') for user-friend. (consider getOption).\n            dataExtent.auto = 1;\n            this.option.range = dataExtent;\n        }\n        else if (isArray(range)) {\n            if (range[0] > range[1]) {\n                range.reverse();\n            }\n            range[0] = Math.max(range[0], dataExtent[0]);\n            range[1] = Math.min(range[1], dataExtent[1]);\n        }\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    completeVisualOption: function () {\n        VisualMapModel.prototype.completeVisualOption.apply(this, arguments);\n\n        each$1(this.stateList, function (state) {\n            var symbolSize = this.option.controller[state].symbolSize;\n            if (symbolSize && symbolSize[0] !== symbolSize[1]) {\n                symbolSize[0] = 0; // For good looking.\n            }\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    setSelected: function (selected) {\n        this.option.range = selected.slice();\n        this._resetRange();\n    },\n\n    /**\n     * @public\n     */\n    getSelected: function () {\n        var dataExtent = this.getExtent();\n\n        var dataInterval = asc(\n            (this.get('range') || []).slice()\n        );\n\n        // Clamp\n        dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]);\n        dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]);\n        dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]);\n        dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]);\n\n        return dataInterval;\n    },\n\n    /**\n     * @override\n     */\n    getValueState: function (value) {\n        var range = this.option.range;\n        var dataExtent = this.getExtent();\n\n        // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'.\n        // range[1] is processed likewise.\n        return (\n            (range[0] <= dataExtent[0] || range[0] <= value)\n            && (range[1] >= dataExtent[1] || value <= range[1])\n        ) ? 'inRange' : 'outOfRange';\n    },\n\n    /**\n     * @params {Array.<number>} range target value: range[0] <= value && value <= range[1]\n     * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]\n     */\n    findTargetDataIndices: function (range) {\n        var result = [];\n\n        this.eachTargetSeries(function (seriesModel) {\n            var dataIndices = [];\n            var data = seriesModel.getData();\n\n            data.each(this.getDataDimension(data), function (value, dataIndex) {\n                range[0] <= value && value <= range[1] && dataIndices.push(dataIndex);\n            }, this);\n\n            result.push({seriesId: seriesModel.id, dataIndex: dataIndices});\n        }, this);\n\n        return result;\n    },\n\n    /**\n     * @implement\n     */\n    getVisualMeta: function (getColorVisual) {\n        var oVals = getColorStopValues(this, 'outOfRange', this.getExtent());\n        var iVals = getColorStopValues(this, 'inRange', this.option.range.slice());\n        var stops = [];\n\n        function setStop(value, valueState) {\n            stops.push({\n                value: value,\n                color: getColorVisual(value, valueState)\n            });\n        }\n\n        // Format to: outOfRange -- inRange -- outOfRange.\n        var iIdx = 0;\n        var oIdx = 0;\n        var iLen = iVals.length;\n        var oLen = oVals.length;\n\n        for (; oIdx < oLen && (!iVals.length || oVals[oIdx] <= iVals[0]); oIdx++) {\n            // If oVal[oIdx] === iVals[iIdx], oVal[oIdx] should be ignored.\n            if (oVals[oIdx] < iVals[iIdx]) {\n                setStop(oVals[oIdx], 'outOfRange');\n            }\n        }\n        for (var first = 1; iIdx < iLen; iIdx++, first = 0) {\n            // If range is full, value beyond min, max will be clamped.\n            // make a singularity\n            first && stops.length && setStop(iVals[iIdx], 'outOfRange');\n            setStop(iVals[iIdx], 'inRange');\n        }\n        for (var first = 1; oIdx < oLen; oIdx++) {\n            if (!iVals.length || iVals[iVals.length - 1] < oVals[oIdx]) {\n                // make a singularity\n                if (first) {\n                    stops.length && setStop(stops[stops.length - 1].value, 'outOfRange');\n                    first = 0;\n                }\n                setStop(oVals[oIdx], 'outOfRange');\n            }\n        }\n\n        var stopsLen = stops.length;\n\n        return {\n            stops: stops,\n            outerColors: [\n                stopsLen ? stops[0].color : 'transparent',\n                stopsLen ? stops[stopsLen - 1].color : 'transparent'\n            ]\n        };\n    }\n\n});\n\nfunction getColorStopValues(visualMapModel, valueState, dataExtent) {\n    if (dataExtent[0] === dataExtent[1]) {\n        return dataExtent.slice();\n    }\n\n    // When using colorHue mapping, it is not linear color any more.\n    // Moreover, canvas gradient seems not to be accurate linear.\n    // FIXME\n    // Should be arbitrary value 100? or based on pixel size?\n    var count = 200;\n    var step = (dataExtent[1] - dataExtent[0]) / count;\n\n    var value = dataExtent[0];\n    var stopValues = [];\n    for (var i = 0; i <= count && value < dataExtent[1]; i++) {\n        stopValues.push(value);\n        value += step;\n    }\n    stopValues.push(dataExtent[1]);\n\n    return stopValues;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar VisualMapView = extendComponentView({\n\n    type: 'visualMap',\n\n    /**\n     * @readOnly\n     * @type {Object}\n     */\n    autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},\n\n    init: function (ecModel, api) {\n        /**\n         * @readOnly\n         * @type {module:echarts/model/Global}\n         */\n        this.ecModel = ecModel;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this.api = api;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/component/visualMap/visualMapModel}\n         */\n        this.visualMapModel;\n    },\n\n    /**\n     * @protected\n     */\n    render: function (visualMapModel, ecModel, api, payload) {\n        this.visualMapModel = visualMapModel;\n\n        if (visualMapModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        this.doRender.apply(this, arguments);\n    },\n\n    /**\n     * @protected\n     */\n    renderBackground: function (group) {\n        var visualMapModel = this.visualMapModel;\n        var padding = normalizeCssArray$1(visualMapModel.get('padding') || 0);\n        var rect = group.getBoundingRect();\n\n        group.add(new Rect({\n            z2: -1, // Lay background rect on the lowest layer.\n            silent: true,\n            shape: {\n                x: rect.x - padding[3],\n                y: rect.y - padding[0],\n                width: rect.width + padding[3] + padding[1],\n                height: rect.height + padding[0] + padding[2]\n            },\n            style: {\n                fill: visualMapModel.get('backgroundColor'),\n                stroke: visualMapModel.get('borderColor'),\n                lineWidth: visualMapModel.get('borderWidth')\n            }\n        }));\n    },\n\n    /**\n     * @protected\n     * @param {number} targetValue can be Infinity or -Infinity\n     * @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize'\n     * @param {Object} [opts]\n     * @param {string=} [opts.forceState] Specify state, instead of using getValueState method.\n     * @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget.\n     * @return {*} Visual value.\n     */\n    getControllerVisual: function (targetValue, visualCluster, opts) {\n        opts = opts || {};\n\n        var forceState = opts.forceState;\n        var visualMapModel = this.visualMapModel;\n        var visualObj = {};\n\n        // Default values.\n        if (visualCluster === 'symbol') {\n            visualObj.symbol = visualMapModel.get('itemSymbol');\n        }\n        if (visualCluster === 'color') {\n            var defaultColor = visualMapModel.get('contentColor');\n            visualObj.color = defaultColor;\n        }\n\n        function getter(key) {\n            return visualObj[key];\n        }\n\n        function setter(key, value) {\n            visualObj[key] = value;\n        }\n\n        var mappings = visualMapModel.controllerVisuals[\n            forceState || visualMapModel.getValueState(targetValue)\n        ];\n        var visualTypes = VisualMapping.prepareVisualTypes(mappings);\n\n        each$1(visualTypes, function (type) {\n            var visualMapping = mappings[type];\n            if (opts.convertOpacityToAlpha && type === 'opacity') {\n                type = 'colorAlpha';\n                visualMapping = mappings.__alphaForOpacity;\n            }\n            if (VisualMapping.dependsOn(type, visualCluster)) {\n                visualMapping && visualMapping.applyVisual(\n                    targetValue, getter, setter\n                );\n            }\n        });\n\n        return visualObj[visualCluster];\n    },\n\n    /**\n     * @protected\n     */\n    positionGroup: function (group) {\n        var model = this.visualMapModel;\n        var api = this.api;\n\n        positionElement(\n            group,\n            model.getBoxLayoutParams(),\n            {width: api.getWidth(), height: api.getHeight()}\n        );\n    },\n\n    /**\n     * @protected\n     * @abstract\n     */\n    doRender: noop\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/component/visualMap/VisualMapModel} visualMapModel\\\n * @param {module:echarts/ExtensionAPI} api\n * @param {Array.<number>} itemSize always [short, long]\n * @return {string} 'left' or 'right' or 'top' or 'bottom'\n */\nfunction getItemAlign(visualMapModel, api, itemSize) {\n    var modelOption = visualMapModel.option;\n    var itemAlign = modelOption.align;\n\n    if (itemAlign != null && itemAlign !== 'auto') {\n        return itemAlign;\n    }\n\n    // Auto decision align.\n    var ecSize = {width: api.getWidth(), height: api.getHeight()};\n    var realIndex = modelOption.orient === 'horizontal' ? 1 : 0;\n\n    var paramsSet = [\n        ['left', 'right', 'width'],\n        ['top', 'bottom', 'height']\n    ];\n    var reals = paramsSet[realIndex];\n    var fakeValue = [0, null, 10];\n\n    var layoutInput = {};\n    for (var i = 0; i < 3; i++) {\n        layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i];\n        layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]];\n    }\n\n    var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex];\n    var rect = getLayoutRect(layoutInput, ecSize, modelOption.padding);\n\n    return reals[\n        (rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5\n            < ecSize[rParam[1]] * 0.5 ? 0 : 1\n    ];\n}\n\n/**\n * Prepare dataIndex for outside usage, where dataIndex means rawIndex, and\n * dataIndexInside means filtered index.\n */\nfunction convertDataIndex(batch) {\n    each$1(batch || [], function (batchItem) {\n        if (batch.dataIndex != null) {\n            batch.dataIndexInside = batch.dataIndex;\n            batch.dataIndex = null;\n        }\n    });\n    return batch;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar linearMap$3 = linearMap;\nvar each$26 = each$1;\nvar mathMin$7 = Math.min;\nvar mathMax$7 = Math.max;\n\n// Arbitrary value\nvar HOVER_LINK_SIZE = 12;\nvar HOVER_LINK_OUT = 6;\n\n// Notice:\n// Any \"interval\" should be by the order of [low, high].\n// \"handle0\" (handleIndex === 0) maps to\n// low data value: this._dataInterval[0] and has low coord.\n// \"handle1\" (handleIndex === 1) maps to\n// high data value: this._dataInterval[1] and has high coord.\n// The logic of transform is implemented in this._createBarGroup.\n\nvar ContinuousView = VisualMapView.extend({\n\n    type: 'visualMap.continuous',\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        ContinuousView.superApply(this, 'init', arguments);\n\n        /**\n         * @private\n         */\n        this._shapes = {};\n\n        /**\n         * @private\n         */\n        this._dataInterval = [];\n\n        /**\n         * @private\n         */\n        this._handleEnds = [];\n\n        /**\n         * @private\n         */\n        this._orient;\n\n        /**\n         * @private\n         */\n        this._useHandle;\n\n        /**\n         * @private\n         */\n        this._hoverLinkDataIndices = [];\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._hovering;\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    doRender: function (visualMapModel, ecModel, api, payload) {\n        if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) {\n            this._buildView();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _buildView: function () {\n        this.group.removeAll();\n\n        var visualMapModel = this.visualMapModel;\n        var thisGroup = this.group;\n\n        this._orient = visualMapModel.get('orient');\n        this._useHandle = visualMapModel.get('calculable');\n\n        this._resetInterval();\n\n        this._renderBar(thisGroup);\n\n        var dataRangeText = visualMapModel.get('text');\n        this._renderEndsText(thisGroup, dataRangeText, 0);\n        this._renderEndsText(thisGroup, dataRangeText, 1);\n\n        // Do this for background size calculation.\n        this._updateView(true);\n\n        // After updating view, inner shapes is built completely,\n        // and then background can be rendered.\n        this.renderBackground(thisGroup);\n\n        // Real update view\n        this._updateView();\n\n        this._enableHoverLinkToSeries();\n        this._enableHoverLinkFromSeries();\n\n        this.positionGroup(thisGroup);\n    },\n\n    /**\n     * @private\n     */\n    _renderEndsText: function (group, dataRangeText, endsIndex) {\n        if (!dataRangeText) {\n            return;\n        }\n\n        // Compatible with ec2, text[0] map to high value, text[1] map low value.\n        var text = dataRangeText[1 - endsIndex];\n        text = text != null ? text + '' : '';\n\n        var visualMapModel = this.visualMapModel;\n        var textGap = visualMapModel.get('textGap');\n        var itemSize = visualMapModel.itemSize;\n\n        var barGroup = this._shapes.barGroup;\n        var position = this._applyTransform(\n            [\n                itemSize[0] / 2,\n                endsIndex === 0 ? -textGap : itemSize[1] + textGap\n            ],\n            barGroup\n        );\n        var align = this._applyTransform(\n            endsIndex === 0 ? 'bottom' : 'top',\n            barGroup\n        );\n        var orient = this._orient;\n        var textStyleModel = this.visualMapModel.textStyleModel;\n\n        this.group.add(new Text({\n            style: {\n                x: position[0],\n                y: position[1],\n                textVerticalAlign: orient === 'horizontal' ? 'middle' : align,\n                textAlign: orient === 'horizontal' ? align : 'center',\n                text: text,\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        }));\n    },\n\n    /**\n     * @private\n     */\n    _renderBar: function (targetGroup) {\n        var visualMapModel = this.visualMapModel;\n        var shapes = this._shapes;\n        var itemSize = visualMapModel.itemSize;\n        var orient = this._orient;\n        var useHandle = this._useHandle;\n        var itemAlign = getItemAlign(visualMapModel, this.api, itemSize);\n        var barGroup = shapes.barGroup = this._createBarGroup(itemAlign);\n\n        // Bar\n        barGroup.add(shapes.outOfRange = createPolygon());\n        barGroup.add(shapes.inRange = createPolygon(\n            null,\n            useHandle ? getCursor$1(this._orient) : null,\n            bind(this._dragHandle, this, 'all', false),\n            bind(this._dragHandle, this, 'all', true)\n        ));\n\n        var textRect = visualMapModel.textStyleModel.getTextRect('国');\n        var textSize = mathMax$7(textRect.width, textRect.height);\n\n        // Handle\n        if (useHandle) {\n            shapes.handleThumbs = [];\n            shapes.handleLabels = [];\n            shapes.handleLabelPoints = [];\n\n            this._createHandle(barGroup, 0, itemSize, textSize, orient, itemAlign);\n            this._createHandle(barGroup, 1, itemSize, textSize, orient, itemAlign);\n        }\n\n        this._createIndicator(barGroup, itemSize, textSize, orient);\n\n        targetGroup.add(barGroup);\n    },\n\n    /**\n     * @private\n     */\n    _createHandle: function (barGroup, handleIndex, itemSize, textSize, orient) {\n        var onDrift = bind(this._dragHandle, this, handleIndex, false);\n        var onDragEnd = bind(this._dragHandle, this, handleIndex, true);\n        var handleThumb = createPolygon(\n            createHandlePoints(handleIndex, textSize),\n            getCursor$1(this._orient),\n            onDrift,\n            onDragEnd\n        );\n        handleThumb.position[0] = itemSize[0];\n        barGroup.add(handleThumb);\n\n        // Text is always horizontal layout but should not be effected by\n        // transform (orient/inverse). So label is built separately but not\n        // use zrender/graphic/helper/RectText, and is located based on view\n        // group (according to handleLabelPoint) but not barGroup.\n        var textStyleModel = this.visualMapModel.textStyleModel;\n        var handleLabel = new Text({\n            draggable: true,\n            drift: onDrift,\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragend: onDragEnd,\n            style: {\n                x: 0, y: 0, text: '',\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        });\n        this.group.add(handleLabel);\n\n        var handleLabelPoint = [\n            orient === 'horizontal'\n                ? textSize / 2\n                : textSize * 1.5,\n            orient === 'horizontal'\n                ? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5))\n                : (handleIndex === 0 ? -textSize / 2 : textSize / 2)\n        ];\n\n        var shapes = this._shapes;\n        shapes.handleThumbs[handleIndex] = handleThumb;\n        shapes.handleLabelPoints[handleIndex] = handleLabelPoint;\n        shapes.handleLabels[handleIndex] = handleLabel;\n    },\n\n    /**\n     * @private\n     */\n    _createIndicator: function (barGroup, itemSize, textSize, orient) {\n        var indicator = createPolygon([[0, 0]], 'move');\n        indicator.position[0] = itemSize[0];\n        indicator.attr({invisible: true, silent: true});\n        barGroup.add(indicator);\n\n        var textStyleModel = this.visualMapModel.textStyleModel;\n        var indicatorLabel = new Text({\n            silent: true,\n            invisible: true,\n            style: {\n                x: 0, y: 0, text: '',\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        });\n        this.group.add(indicatorLabel);\n\n        var indicatorLabelPoint = [\n            orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT + 3,\n            0\n        ];\n\n        var shapes = this._shapes;\n        shapes.indicator = indicator;\n        shapes.indicatorLabel = indicatorLabel;\n        shapes.indicatorLabelPoint = indicatorLabelPoint;\n    },\n\n    /**\n     * @private\n     */\n    _dragHandle: function (handleIndex, isEnd, dx, dy) {\n        if (!this._useHandle) {\n            return;\n        }\n\n        this._dragging = !isEnd;\n\n        if (!isEnd) {\n            // Transform dx, dy to bar coordination.\n            var vertex = this._applyTransform([dx, dy], this._shapes.barGroup, true);\n            this._updateInterval(handleIndex, vertex[1]);\n\n            // Considering realtime, update view should be executed\n            // before dispatch action.\n            this._updateView();\n        }\n\n        // dragEnd do not dispatch action when realtime.\n        if (isEnd === !this.visualMapModel.get('realtime')) { // jshint ignore:line\n            this.api.dispatchAction({\n                type: 'selectDataRange',\n                from: this.uid,\n                visualMapId: this.visualMapModel.id,\n                selected: this._dataInterval.slice()\n            });\n        }\n\n        if (isEnd) {\n            !this._hovering && this._clearHoverLinkToSeries();\n        }\n        else if (useHoverLinkOnHandle(this.visualMapModel)) {\n            this._doHoverLinkToSeries(this._handleEnds[handleIndex], false);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var visualMapModel = this.visualMapModel;\n\n        var dataInterval = this._dataInterval = visualMapModel.getSelected();\n        var dataExtent = visualMapModel.getExtent();\n        var sizeExtent = [0, visualMapModel.itemSize[1]];\n\n        this._handleEnds = [\n            linearMap$3(dataInterval[0], dataExtent, sizeExtent, true),\n            linearMap$3(dataInterval[1], dataExtent, sizeExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} dx\n     * @param {number} dy\n     */\n    _updateInterval: function (handleIndex, delta) {\n        delta = delta || 0;\n        var visualMapModel = this.visualMapModel;\n        var handleEnds = this._handleEnds;\n        var sizeExtent = [0, visualMapModel.itemSize[1]];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            sizeExtent,\n            handleIndex,\n            // cross is forbiden\n            0\n        );\n\n        var dataExtent = visualMapModel.getExtent();\n        // Update data interval.\n        this._dataInterval = [\n            linearMap$3(handleEnds[0], sizeExtent, dataExtent, true),\n            linearMap$3(handleEnds[1], sizeExtent, dataExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (forSketch) {\n        var visualMapModel = this.visualMapModel;\n        var dataExtent = visualMapModel.getExtent();\n        var shapes = this._shapes;\n\n        var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]];\n        var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds;\n\n        var visualInRange = this._createBarVisual(\n            this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange'\n        );\n        var visualOutOfRange = this._createBarVisual(\n            dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange'\n        );\n\n        shapes.inRange\n            .setStyle({\n                fill: visualInRange.barColor,\n                opacity: visualInRange.opacity\n            })\n            .setShape('points', visualInRange.barPoints);\n        shapes.outOfRange\n            .setStyle({\n                fill: visualOutOfRange.barColor,\n                opacity: visualOutOfRange.opacity\n            })\n            .setShape('points', visualOutOfRange.barPoints);\n\n        this._updateHandle(inRangeHandleEnds, visualInRange);\n    },\n\n    /**\n     * @private\n     */\n    _createBarVisual: function (dataInterval, dataExtent, handleEnds, forceState) {\n        var opts = {\n            forceState: forceState,\n            convertOpacityToAlpha: true\n        };\n        var colorStops = this._makeColorGradient(dataInterval, opts);\n\n        var symbolSizes = [\n            this.getControllerVisual(dataInterval[0], 'symbolSize', opts),\n            this.getControllerVisual(dataInterval[1], 'symbolSize', opts)\n        ];\n        var barPoints = this._createBarPoints(handleEnds, symbolSizes);\n\n        return {\n            barColor: new LinearGradient(0, 0, 0, 1, colorStops),\n            barPoints: barPoints,\n            handlesColor: [\n                colorStops[0].color,\n                colorStops[colorStops.length - 1].color\n            ]\n        };\n    },\n\n    /**\n     * @private\n     */\n    _makeColorGradient: function (dataInterval, opts) {\n        // Considering colorHue, which is not linear, so we have to sample\n        // to calculate gradient color stops, but not only caculate head\n        // and tail.\n        var sampleNumber = 100; // Arbitrary value.\n        var colorStops = [];\n        var step = (dataInterval[1] - dataInterval[0]) / sampleNumber;\n\n        colorStops.push({\n            color: this.getControllerVisual(dataInterval[0], 'color', opts),\n            offset: 0\n        });\n\n        for (var i = 1; i < sampleNumber; i++) {\n            var currValue = dataInterval[0] + step * i;\n            if (currValue > dataInterval[1]) {\n                break;\n            }\n            colorStops.push({\n                color: this.getControllerVisual(currValue, 'color', opts),\n                offset: i / sampleNumber\n            });\n        }\n\n        colorStops.push({\n            color: this.getControllerVisual(dataInterval[1], 'color', opts),\n            offset: 1\n        });\n\n        return colorStops;\n    },\n\n    /**\n     * @private\n     */\n    _createBarPoints: function (handleEnds, symbolSizes) {\n        var itemSize = this.visualMapModel.itemSize;\n\n        return [\n            [itemSize[0] - symbolSizes[0], handleEnds[0]],\n            [itemSize[0], handleEnds[0]],\n            [itemSize[0], handleEnds[1]],\n            [itemSize[0] - symbolSizes[1], handleEnds[1]]\n        ];\n    },\n\n    /**\n     * @private\n     */\n    _createBarGroup: function (itemAlign) {\n        var orient = this._orient;\n        var inverse = this.visualMapModel.get('inverse');\n\n        return new Group(\n            (orient === 'horizontal' && !inverse)\n            ? {scale: itemAlign === 'bottom' ? [1, 1] : [-1, 1], rotation: Math.PI / 2}\n            : (orient === 'horizontal' && inverse)\n            ? {scale: itemAlign === 'bottom' ? [-1, 1] : [1, 1], rotation: -Math.PI / 2}\n            : (orient === 'vertical' && !inverse)\n            ? {scale: itemAlign === 'left' ? [1, -1] : [-1, -1]}\n            : {scale: itemAlign === 'left' ? [1, 1] : [-1, 1]}\n        );\n    },\n\n    /**\n     * @private\n     */\n    _updateHandle: function (handleEnds, visualInRange) {\n        if (!this._useHandle) {\n            return;\n        }\n\n        var shapes = this._shapes;\n        var visualMapModel = this.visualMapModel;\n        var handleThumbs = shapes.handleThumbs;\n        var handleLabels = shapes.handleLabels;\n\n        each$26([0, 1], function (handleIndex) {\n            var handleThumb = handleThumbs[handleIndex];\n            handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]);\n            handleThumb.position[1] = handleEnds[handleIndex];\n\n            // Update handle label position.\n            var textPoint = applyTransform$1(\n                shapes.handleLabelPoints[handleIndex],\n                getTransform(handleThumb, this.group)\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                text: visualMapModel.formatValueText(this._dataInterval[handleIndex]),\n                textVerticalAlign: 'middle',\n                textAlign: this._applyTransform(\n                    this._orient === 'horizontal'\n                        ? (handleIndex === 0 ? 'bottom' : 'top')\n                        : 'left',\n                    shapes.barGroup\n                )\n            });\n        }, this);\n    },\n\n    /**\n     * @private\n     * @param {number} cursorValue\n     * @param {number} textValue\n     * @param {string} [rangeSymbol]\n     * @param {number} [halfHoverLinkSize]\n     */\n    _showIndicator: function (cursorValue, textValue, rangeSymbol, halfHoverLinkSize) {\n        var visualMapModel = this.visualMapModel;\n        var dataExtent = visualMapModel.getExtent();\n        var itemSize = visualMapModel.itemSize;\n        var sizeExtent = [0, itemSize[1]];\n        var pos = linearMap$3(cursorValue, dataExtent, sizeExtent, true);\n\n        var shapes = this._shapes;\n        var indicator = shapes.indicator;\n        if (!indicator) {\n            return;\n        }\n\n        indicator.position[1] = pos;\n        indicator.attr('invisible', false);\n        indicator.setShape('points', createIndicatorPoints(\n            !!rangeSymbol, halfHoverLinkSize, pos, itemSize[1]\n        ));\n\n        var opts = {convertOpacityToAlpha: true};\n        var color = this.getControllerVisual(cursorValue, 'color', opts);\n        indicator.setStyle('fill', color);\n\n        // Update handle label position.\n        var textPoint = applyTransform$1(\n            shapes.indicatorLabelPoint,\n            getTransform(indicator, this.group)\n        );\n\n        var indicatorLabel = shapes.indicatorLabel;\n        indicatorLabel.attr('invisible', false);\n        var align = this._applyTransform('left', shapes.barGroup);\n        var orient = this._orient;\n        indicatorLabel.setStyle({\n            text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue),\n            textVerticalAlign: orient === 'horizontal' ? align : 'middle',\n            textAlign: orient === 'horizontal' ? 'center' : align,\n            x: textPoint[0],\n            y: textPoint[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLinkToSeries: function () {\n        var self = this;\n        this._shapes.barGroup\n\n            .on('mousemove', function (e) {\n                self._hovering = true;\n\n                if (!self._dragging) {\n                    var itemSize = self.visualMapModel.itemSize;\n                    var pos = self._applyTransform(\n                        [e.offsetX, e.offsetY], self._shapes.barGroup, true, true\n                    );\n                    // For hover link show when hover handle, which might be\n                    // below or upper than sizeExtent.\n                    pos[1] = mathMin$7(mathMax$7(0, pos[1]), itemSize[1]);\n                    self._doHoverLinkToSeries(\n                        pos[1],\n                        0 <= pos[0] && pos[0] <= itemSize[0]\n                    );\n                }\n            })\n\n            .on('mouseout', function () {\n                // When mouse is out of handle, hoverLink still need\n                // to be displayed when realtime is set as false.\n                self._hovering = false;\n                !self._dragging && self._clearHoverLinkToSeries();\n            });\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLinkFromSeries: function () {\n        var zr = this.api.getZr();\n\n        if (this.visualMapModel.option.hoverLink) {\n            zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this);\n            zr.on('mouseout', this._hideIndicator, this);\n        }\n        else {\n            this._clearHoverLinkFromSeries();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _doHoverLinkToSeries: function (cursorPos, hoverOnBar) {\n        var visualMapModel = this.visualMapModel;\n        var itemSize = visualMapModel.itemSize;\n\n        if (!visualMapModel.option.hoverLink) {\n            return;\n        }\n\n        var sizeExtent = [0, itemSize[1]];\n        var dataExtent = visualMapModel.getExtent();\n\n        // For hover link show when hover handle, which might be below or upper than sizeExtent.\n        cursorPos = mathMin$7(mathMax$7(sizeExtent[0], cursorPos), sizeExtent[1]);\n\n        var halfHoverLinkSize = getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent);\n        var hoverRange = [cursorPos - halfHoverLinkSize, cursorPos + halfHoverLinkSize];\n        var cursorValue = linearMap$3(cursorPos, sizeExtent, dataExtent, true);\n        var valueRange = [\n            linearMap$3(hoverRange[0], sizeExtent, dataExtent, true),\n            linearMap$3(hoverRange[1], sizeExtent, dataExtent, true)\n        ];\n        // Consider data range is out of visualMap range, see test/visualMap-continuous.html,\n        // where china and india has very large population.\n        hoverRange[0] < sizeExtent[0] && (valueRange[0] = -Infinity);\n        hoverRange[1] > sizeExtent[1] && (valueRange[1] = Infinity);\n\n        // Do not show indicator when mouse is over handle,\n        // otherwise labels overlap, especially when dragging.\n        if (hoverOnBar) {\n            if (valueRange[0] === -Infinity) {\n                this._showIndicator(cursorValue, valueRange[1], '< ', halfHoverLinkSize);\n            }\n            else if (valueRange[1] === Infinity) {\n                this._showIndicator(cursorValue, valueRange[0], '> ', halfHoverLinkSize);\n            }\n            else {\n                this._showIndicator(cursorValue, cursorValue, '≈ ', halfHoverLinkSize);\n            }\n        }\n\n        // When realtime is set as false, handles, which are in barGroup,\n        // also trigger hoverLink, which help user to realize where they\n        // focus on when dragging. (see test/heatmap-large.html)\n        // When realtime is set as true, highlight will not show when hover\n        // handle, because the label on handle, which displays a exact value\n        // but not range, might mislead users.\n        var oldBatch = this._hoverLinkDataIndices;\n        var newBatch = [];\n        if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) {\n            newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);\n        }\n\n        var resultBatches = compressBatches(oldBatch, newBatch);\n\n        this._dispatchHighDown('downplay', convertDataIndex(resultBatches[0]));\n        this._dispatchHighDown('highlight', convertDataIndex(resultBatches[1]));\n    },\n\n    /**\n     * @private\n     */\n    _hoverLinkFromSeriesMouseOver: function (e) {\n        var el = e.target;\n        var visualMapModel = this.visualMapModel;\n\n        if (!el || el.dataIndex == null) {\n            return;\n        }\n\n        var dataModel = this.ecModel.getSeriesByIndex(el.seriesIndex);\n\n        if (!visualMapModel.isTargetSeries(dataModel)) {\n            return;\n        }\n\n        var data = dataModel.getData(el.dataType);\n        var value = data.get(visualMapModel.getDataDimension(data), el.dataIndex, true);\n\n        if (!isNaN(value)) {\n            this._showIndicator(value, value);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _hideIndicator: function () {\n        var shapes = this._shapes;\n        shapes.indicator && shapes.indicator.attr('invisible', true);\n        shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true);\n    },\n\n    /**\n     * @private\n     */\n    _clearHoverLinkToSeries: function () {\n        this._hideIndicator();\n\n        var indices = this._hoverLinkDataIndices;\n        this._dispatchHighDown('downplay', convertDataIndex(indices));\n\n        indices.length = 0;\n    },\n\n    /**\n     * @private\n     */\n    _clearHoverLinkFromSeries: function () {\n        this._hideIndicator();\n\n        var zr = this.api.getZr();\n        zr.off('mouseover', this._hoverLinkFromSeriesMouseOver);\n        zr.off('mouseout', this._hideIndicator);\n    },\n\n    /**\n     * @private\n     */\n    _applyTransform: function (vertex, element, inverse, global) {\n        var transform = getTransform(element, global ? null : this.group);\n\n        return graphic[\n            isArray(vertex) ? 'applyTransform' : 'transformDirection'\n        ](vertex, transform, inverse);\n    },\n\n    /**\n     * @private\n     */\n    _dispatchHighDown: function (type, batch) {\n        batch && batch.length && this.api.dispatchAction({\n            type: type,\n            batch: batch\n        });\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clearHoverLinkFromSeries();\n        this._clearHoverLinkToSeries();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearHoverLinkFromSeries();\n        this._clearHoverLinkToSeries();\n    }\n\n});\n\nfunction createPolygon(points, cursor, onDrift, onDragEnd) {\n    return new Polygon({\n        shape: {points: points},\n        draggable: !!onDrift,\n        cursor: cursor,\n        drift: onDrift,\n        onmousemove: function (e) {\n            // Fot mobile devicem, prevent screen slider on the button.\n            stop(e.event);\n        },\n        ondragend: onDragEnd\n    });\n}\n\nfunction createHandlePoints(handleIndex, textSize) {\n    return handleIndex === 0\n        ? [[0, 0], [textSize, 0], [textSize, -textSize]]\n        : [[0, 0], [textSize, 0], [textSize, textSize]];\n}\n\nfunction createIndicatorPoints(isRange, halfHoverLinkSize, pos, extentMax) {\n    return isRange\n        ? [ // indicate range\n            [0, -mathMin$7(halfHoverLinkSize, mathMax$7(pos, 0))],\n            [HOVER_LINK_OUT, 0],\n            [0, mathMin$7(halfHoverLinkSize, mathMax$7(extentMax - pos, 0))]\n        ]\n        : [ // indicate single value\n            [0, 0], [5, -5], [5, 5]\n        ];\n}\n\nfunction getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent) {\n    var halfHoverLinkSize = HOVER_LINK_SIZE / 2;\n    var hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize');\n    if (hoverLinkDataSize) {\n        halfHoverLinkSize = linearMap$3(hoverLinkDataSize, dataExtent, sizeExtent, true) / 2;\n    }\n    return halfHoverLinkSize;\n}\n\nfunction useHoverLinkOnHandle(visualMapModel) {\n    var hoverLinkOnHandle = visualMapModel.get('hoverLinkOnHandle');\n    return !!(hoverLinkOnHandle == null ? visualMapModel.get('realtime') : hoverLinkOnHandle);\n}\n\nfunction getCursor$1(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar actionInfo$2 = {\n    type: 'selectDataRange',\n    event: 'dataRangeSelected',\n    // FIXME use updateView appears wrong\n    update: 'update'\n};\n\nregisterAction(actionInfo$2, function (payload, ecModel) {\n\n    ecModel.eachComponent({mainType: 'visualMap', query: payload}, function (model) {\n        model.setSelected(payload.selected);\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PiecewiseModel = VisualMapModel.extend({\n\n    type: 'visualMap.piecewise',\n\n    /**\n     * Order Rule:\n     *\n     * option.categories / option.pieces / option.text / option.selected:\n     *     If !option.inverse,\n     *     Order when vertical: ['top', ..., 'bottom'].\n     *     Order when horizontal: ['left', ..., 'right'].\n     *     If option.inverse, the meaning of\n     *     the order should be reversed.\n     *\n     * this._pieceList:\n     *     The order is always [low, ..., high].\n     *\n     * Mapping from location to low-high:\n     *     If !option.inverse\n     *     When vertical, top is high.\n     *     When horizontal, right is high.\n     *     If option.inverse, reverse.\n     */\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        selected: null,             // Object. If not specified, means selected.\n                                    // When pieces and splitNumber: {'0': true, '5': true}\n                                    // When categories: {'cate1': false, 'cate3': true}\n                                    // When selected === false, means all unselected.\n\n        minOpen: false,             // Whether include values that smaller than `min`.\n        maxOpen: false,             // Whether include values that bigger than `max`.\n\n        align: 'auto',              // 'auto', 'left', 'right'\n        itemWidth: 20,              // When put the controller vertically, it is the length of\n                                    // horizontal side of each item. Otherwise, vertical side.\n        itemHeight: 14,             // When put the controller vertically, it is the length of\n                                    // vertical side of each item. Otherwise, horizontal side.\n        itemSymbol: 'roundRect',\n        pieceList: null,            // Each item is Object, with some of those attrs:\n                                    // {min, max, lt, gt, lte, gte, value,\n                                    // color, colorSaturation, colorAlpha, opacity,\n                                    // symbol, symbolSize}, which customize the range or visual\n                                    // coding of the certain piece. Besides, see \"Order Rule\".\n        categories: null,           // category names, like: ['some1', 'some2', 'some3'].\n                                    // Attr min/max are ignored when categories set. See \"Order Rule\"\n        splitNumber: 5,             // If set to 5, auto split five pieces equally.\n                                    // If set to 0 and component type not set, component type will be\n                                    // determined as \"continuous\". (It is less reasonable but for ec2\n                                    // compatibility, see echarts/component/visualMap/typeDefaulter)\n        selectedMode: 'multiple',   // Can be 'multiple' or 'single'.\n        itemGap: 10,                // The gap between two items, in px.\n        hoverLink: true,            // Enable hover highlight.\n\n        showLabel: null             // By default, when text is used, label will hide (the logic\n                                    // is remained for compatibility reason)\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        PiecewiseModel.superApply(this, 'optionUpdated', arguments);\n\n        /**\n         * The order is always [low, ..., high].\n         * [{text: string, interval: Array.<number>}, ...]\n         * @private\n         * @type {Array.<Object>}\n         */\n        this._pieceList = [];\n\n        this.resetExtent();\n\n        /**\n         * 'pieces', 'categories', 'splitNumber'\n         * @type {string}\n         */\n        var mode = this._mode = this._determineMode();\n\n        resetMethods[this._mode].call(this);\n\n        this._resetSelected(newOption, isInit);\n\n        var categories = this.option.categories;\n\n        this.resetVisual(function (mappingOption, state) {\n            if (mode === 'categories') {\n                mappingOption.mappingMethod = 'category';\n                mappingOption.categories = clone(categories);\n            }\n            else {\n                mappingOption.dataExtent = this.getExtent();\n                mappingOption.mappingMethod = 'piecewise';\n                mappingOption.pieceList = map(this._pieceList, function (piece) {\n                    var piece = clone(piece);\n                    if (state !== 'inRange') {\n                        // FIXME\n                        // outOfRange do not support special visual in pieces.\n                        piece.visual = null;\n                    }\n                    return piece;\n                });\n            }\n        });\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    completeVisualOption: function () {\n        // Consider this case:\n        // visualMap: {\n        //      pieces: [{symbol: 'circle', lt: 0}, {symbol: 'rect', gte: 0}]\n        // }\n        // where no inRange/outOfRange set but only pieces. So we should make\n        // default inRange/outOfRange for this case, otherwise visuals that only\n        // appear in `pieces` will not be taken into account in visual encoding.\n\n        var option = this.option;\n        var visualTypesInPieces = {};\n        var visualTypes = VisualMapping.listVisualTypes();\n        var isCategory = this.isCategory();\n\n        each$1(option.pieces, function (piece) {\n            each$1(visualTypes, function (visualType) {\n                if (piece.hasOwnProperty(visualType)) {\n                    visualTypesInPieces[visualType] = 1;\n                }\n            });\n        });\n\n        each$1(visualTypesInPieces, function (v, visualType) {\n            var exists = 0;\n            each$1(this.stateList, function (state) {\n                exists |= has(option, state, visualType)\n                    || has(option.target, state, visualType);\n            }, this);\n\n            !exists && each$1(this.stateList, function (state) {\n                (option[state] || (option[state] = {}))[visualType] = visualDefault.get(\n                    visualType, state === 'inRange' ? 'active' : 'inactive', isCategory\n                );\n            });\n        }, this);\n\n        function has(obj, state, visualType) {\n            return obj && obj[state] && (\n                isObject$1(obj[state])\n                    ? obj[state].hasOwnProperty(visualType)\n                    : obj[state] === visualType // e.g., inRange: 'symbol'\n            );\n        }\n\n        VisualMapModel.prototype.completeVisualOption.apply(this, arguments);\n    },\n\n    _resetSelected: function (newOption, isInit) {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n\n        // Selected do not merge but all override.\n        var selected = (isInit ? thisOption : newOption).selected || {};\n        thisOption.selected = selected;\n\n        // Consider 'not specified' means true.\n        each$1(pieceList, function (piece, index) {\n            var key = this.getSelectedMapKey(piece);\n            if (!selected.hasOwnProperty(key)) {\n                selected[key] = true;\n            }\n        }, this);\n\n        if (thisOption.selectedMode === 'single') {\n            // Ensure there is only one selected.\n            var hasSel = false;\n\n            each$1(pieceList, function (piece, index) {\n                var key = this.getSelectedMapKey(piece);\n                if (selected[key]) {\n                    hasSel\n                        ? (selected[key] = false)\n                        : (hasSel = true);\n                }\n            }, this);\n        }\n        // thisOption.selectedMode === 'multiple', default: all selected.\n    },\n\n    /**\n     * @public\n     */\n    getSelectedMapKey: function (piece) {\n        return this._mode === 'categories'\n            ? piece.value + '' : piece.index + '';\n    },\n\n    /**\n     * @public\n     */\n    getPieceList: function () {\n        return this._pieceList;\n    },\n\n    /**\n     * @private\n     * @return {string}\n     */\n    _determineMode: function () {\n        var option = this.option;\n\n        return option.pieces && option.pieces.length > 0\n            ? 'pieces'\n            : this.option.categories\n            ? 'categories'\n            : 'splitNumber';\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    setSelected: function (selected) {\n        this.option.selected = clone(selected);\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    getValueState: function (value) {\n        var index = VisualMapping.findPieceIndex(value, this._pieceList);\n\n        return index != null\n            ? (this.option.selected[this.getSelectedMapKey(this._pieceList[index])]\n                ? 'inRange' : 'outOfRange'\n            )\n            : 'outOfRange';\n    },\n\n    /**\n     * @public\n     * @params {number} pieceIndex piece index in visualMapModel.getPieceList()\n     * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]\n     */\n    findTargetDataIndices: function (pieceIndex) {\n        var result = [];\n\n        this.eachTargetSeries(function (seriesModel) {\n            var dataIndices = [];\n            var data = seriesModel.getData();\n\n            data.each(this.getDataDimension(data), function (value, dataIndex) {\n                // Should always base on model pieceList, because it is order sensitive.\n                var pIdx = VisualMapping.findPieceIndex(value, this._pieceList);\n                pIdx === pieceIndex && dataIndices.push(dataIndex);\n            }, this);\n\n            result.push({seriesId: seriesModel.id, dataIndex: dataIndices});\n        }, this);\n\n        return result;\n    },\n\n    /**\n     * @private\n     * @param {Object} piece piece.value or piece.interval is required.\n     * @return {number} Can be Infinity or -Infinity\n     */\n    getRepresentValue: function (piece) {\n        var representValue;\n        if (this.isCategory()) {\n            representValue = piece.value;\n        }\n        else {\n            if (piece.value != null) {\n                representValue = piece.value;\n            }\n            else {\n                var pieceInterval = piece.interval || [];\n                representValue = (pieceInterval[0] === -Infinity && pieceInterval[1] === Infinity)\n                    ? 0\n                    : (pieceInterval[0] + pieceInterval[1]) / 2;\n            }\n        }\n        return representValue;\n    },\n\n    getVisualMeta: function (getColorVisual) {\n        // Do not support category. (category axis is ordinal, numerical)\n        if (this.isCategory()) {\n            return;\n        }\n\n        var stops = [];\n        var outerColors = [];\n        var visualMapModel = this;\n\n        function setStop(interval, valueState) {\n            var representValue = visualMapModel.getRepresentValue({interval: interval});\n            if (!valueState) {\n                valueState = visualMapModel.getValueState(representValue);\n            }\n            var color = getColorVisual(representValue, valueState);\n            if (interval[0] === -Infinity) {\n                outerColors[0] = color;\n            }\n            else if (interval[1] === Infinity) {\n                outerColors[1] = color;\n            }\n            else {\n                stops.push(\n                    {value: interval[0], color: color},\n                    {value: interval[1], color: color}\n                );\n            }\n        }\n\n        // Suplement\n        var pieceList = this._pieceList.slice();\n        if (!pieceList.length) {\n            pieceList.push({interval: [-Infinity, Infinity]});\n        }\n        else {\n            var edge = pieceList[0].interval[0];\n            edge !== -Infinity && pieceList.unshift({interval: [-Infinity, edge]});\n            edge = pieceList[pieceList.length - 1].interval[1];\n            edge !== Infinity && pieceList.push({interval: [edge, Infinity]});\n        }\n\n        var curr = -Infinity;\n        each$1(pieceList, function (piece) {\n            var interval = piece.interval;\n            if (interval) {\n                // Fulfill gap.\n                interval[0] > curr && setStop([curr, interval[0]], 'outOfRange');\n                setStop(interval.slice());\n                curr = interval[1];\n            }\n        }, this);\n\n        return {stops: stops, outerColors: outerColors};\n    }\n\n});\n\n/**\n * Key is this._mode\n * @type {Object}\n * @this {module:echarts/component/viusalMap/PiecewiseMode}\n */\nvar resetMethods = {\n\n    splitNumber: function () {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n        var precision = Math.min(thisOption.precision, 20);\n        var dataExtent = this.getExtent();\n        var splitNumber = thisOption.splitNumber;\n        splitNumber = Math.max(parseInt(splitNumber, 10), 1);\n        thisOption.splitNumber = splitNumber;\n\n        var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber;\n        // Precision auto-adaption\n        while (+splitStep.toFixed(precision) !== splitStep && precision < 5) {\n            precision++;\n        }\n        thisOption.precision = precision;\n        splitStep = +splitStep.toFixed(precision);\n\n        var index = 0;\n\n        if (thisOption.minOpen) {\n            pieceList.push({\n                index: index++,\n                interval: [-Infinity, dataExtent[0]],\n                close: [0, 0]\n            });\n        }\n\n        for (\n            var curr = dataExtent[0], len = index + splitNumber;\n            index < len;\n            curr += splitStep\n        ) {\n            var max = index === splitNumber - 1 ? dataExtent[1] : (curr + splitStep);\n\n            pieceList.push({\n                index: index++,\n                interval: [curr, max],\n                close: [1, 1]\n            });\n        }\n\n        if (thisOption.maxOpen) {\n            pieceList.push({\n                index: index++,\n                interval: [dataExtent[1], Infinity],\n                close: [0, 0]\n            });\n        }\n\n        reformIntervals(pieceList);\n\n        each$1(pieceList, function (piece) {\n            piece.text = this.formatValueText(piece.interval);\n        }, this);\n    },\n\n    categories: function () {\n        var thisOption = this.option;\n        each$1(thisOption.categories, function (cate) {\n            // FIXME category模式也使用pieceList，但在visualMapping中不是使用pieceList。\n            // 是否改一致。\n            this._pieceList.push({\n                text: this.formatValueText(cate, true),\n                value: cate\n            });\n        }, this);\n\n        // See \"Order Rule\".\n        normalizeReverse(thisOption, this._pieceList);\n    },\n\n    pieces: function () {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n\n        each$1(thisOption.pieces, function (pieceListItem, index) {\n\n            if (!isObject$1(pieceListItem)) {\n                pieceListItem = {value: pieceListItem};\n            }\n\n            var item = {text: '', index: index};\n\n            if (pieceListItem.label != null) {\n                item.text = pieceListItem.label;\n            }\n\n            if (pieceListItem.hasOwnProperty('value')) {\n                var value = item.value = pieceListItem.value;\n                item.interval = [value, value];\n                item.close = [1, 1];\n            }\n            else {\n                // `min` `max` is legacy option.\n                // `lt` `gt` `lte` `gte` is recommanded.\n                var interval = item.interval = [];\n                var close = item.close = [0, 0];\n\n                var closeList = [1, 0, 1];\n                var infinityList = [-Infinity, Infinity];\n\n                var useMinMax = [];\n                for (var lg = 0; lg < 2; lg++) {\n                    var names = [['gte', 'gt', 'min'], ['lte', 'lt', 'max']][lg];\n                    for (var i = 0; i < 3 && interval[lg] == null; i++) {\n                        interval[lg] = pieceListItem[names[i]];\n                        close[lg] = closeList[i];\n                        useMinMax[lg] = i === 2;\n                    }\n                    interval[lg] == null && (interval[lg] = infinityList[lg]);\n                }\n                useMinMax[0] && interval[1] === Infinity && (close[0] = 0);\n                useMinMax[1] && interval[0] === -Infinity && (close[1] = 0);\n\n                if (__DEV__) {\n                    if (interval[0] > interval[1]) {\n                        console.warn(\n                            'Piece ' + index + 'is illegal: ' + interval\n                            + ' lower bound should not greater then uppper bound.'\n                        );\n                    }\n                }\n\n                if (interval[0] === interval[1] && close[0] && close[1]) {\n                    // Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}],\n                    // we use value to lift the priority when min === max\n                    item.value = interval[0];\n                }\n            }\n\n            item.visual = VisualMapping.retrieveVisuals(pieceListItem);\n\n            pieceList.push(item);\n\n        }, this);\n\n        // See \"Order Rule\".\n        normalizeReverse(thisOption, pieceList);\n        // Only pieces\n        reformIntervals(pieceList);\n\n        each$1(pieceList, function (piece) {\n            var close = piece.close;\n            var edgeSymbols = [['<', '≤'][close[1]], ['>', '≥'][close[0]]];\n            piece.text = piece.text || this.formatValueText(\n                piece.value != null ? piece.value : piece.interval,\n                false,\n                edgeSymbols\n            );\n        }, this);\n    }\n};\n\nfunction normalizeReverse(thisOption, pieceList) {\n    var inverse = thisOption.inverse;\n    if (thisOption.orient === 'vertical' ? !inverse : inverse) {\n            pieceList.reverse();\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PiecewiseVisualMapView = VisualMapView.extend({\n\n    type: 'visualMap.piecewise',\n\n    /**\n     * @protected\n     * @override\n     */\n    doRender: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        var visualMapModel = this.visualMapModel;\n        var textGap = visualMapModel.get('textGap');\n        var textStyleModel = visualMapModel.textStyleModel;\n        var textFont = textStyleModel.getFont();\n        var textFill = textStyleModel.getTextColor();\n        var itemAlign = this._getItemAlign();\n        var itemSize = visualMapModel.itemSize;\n        var viewData = this._getViewData();\n        var endsText = viewData.endsText;\n        var showLabel = retrieve(visualMapModel.get('showLabel', true), !endsText);\n\n        endsText && this._renderEndsText(\n            thisGroup, endsText[0], itemSize, showLabel, itemAlign\n        );\n\n        each$1(viewData.viewPieceList, renderItem, this);\n\n        endsText && this._renderEndsText(\n            thisGroup, endsText[1], itemSize, showLabel, itemAlign\n        );\n\n        box(\n            visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')\n        );\n\n        this.renderBackground(thisGroup);\n\n        this.positionGroup(thisGroup);\n\n        function renderItem(item) {\n            var piece = item.piece;\n\n            var itemGroup = new Group();\n            itemGroup.onclick = bind(this._onItemClick, this, piece);\n\n            this._enableHoverLink(itemGroup, item.indexInModelPieceList);\n\n            var representValue = visualMapModel.getRepresentValue(piece);\n\n            this._createItemSymbol(\n                itemGroup, representValue, [0, 0, itemSize[0], itemSize[1]]\n            );\n\n            if (showLabel) {\n                var visualState = this.visualMapModel.getValueState(representValue);\n\n                itemGroup.add(new Text({\n                    style: {\n                        x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap,\n                        y: itemSize[1] / 2,\n                        text: piece.text,\n                        textVerticalAlign: 'middle',\n                        textAlign: itemAlign,\n                        textFont: textFont,\n                        textFill: textFill,\n                        opacity: visualState === 'outOfRange' ? 0.5 : 1\n                    }\n                }));\n            }\n\n            thisGroup.add(itemGroup);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLink: function (itemGroup, pieceIndex) {\n        itemGroup\n            .on('mouseover', bind(onHoverLink, this, 'highlight'))\n            .on('mouseout', bind(onHoverLink, this, 'downplay'));\n\n        function onHoverLink(method) {\n            var visualMapModel = this.visualMapModel;\n\n            visualMapModel.option.hoverLink && this.api.dispatchAction({\n                type: method,\n                batch: convertDataIndex(\n                    visualMapModel.findTargetDataIndices(pieceIndex)\n                )\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _getItemAlign: function () {\n        var visualMapModel = this.visualMapModel;\n        var modelOption = visualMapModel.option;\n\n        if (modelOption.orient === 'vertical') {\n            return getItemAlign(\n                visualMapModel, this.api, visualMapModel.itemSize\n            );\n        }\n        else { // horizontal, most case left unless specifying right.\n            var align = modelOption.align;\n            if (!align || align === 'auto') {\n                align = 'left';\n            }\n            return align;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderEndsText: function (group, text, itemSize, showLabel, itemAlign) {\n        if (!text) {\n            return;\n        }\n\n        var itemGroup = new Group();\n        var textStyleModel = this.visualMapModel.textStyleModel;\n\n        itemGroup.add(new Text({\n            style: {\n                x: showLabel ? (itemAlign === 'right' ? itemSize[0] : 0) : itemSize[0] / 2,\n                y: itemSize[1] / 2,\n                textVerticalAlign: 'middle',\n                textAlign: showLabel ? itemAlign : 'center',\n                text: text,\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        }));\n\n        group.add(itemGroup);\n    },\n\n    /**\n     * @private\n     * @return {Object} {peiceList, endsText} The order is the same as screen pixel order.\n     */\n    _getViewData: function () {\n        var visualMapModel = this.visualMapModel;\n\n        var viewPieceList = map(visualMapModel.getPieceList(), function (piece, index) {\n            return {piece: piece, indexInModelPieceList: index};\n        });\n        var endsText = visualMapModel.get('text');\n\n        // Consider orient and inverse.\n        var orient = visualMapModel.get('orient');\n        var inverse = visualMapModel.get('inverse');\n\n        // Order of model pieceList is always [low, ..., high]\n        if (orient === 'horizontal' ? inverse : !inverse) {\n            viewPieceList.reverse();\n        }\n        // Origin order of endsText is [high, low]\n        else if (endsText) {\n            endsText = endsText.slice().reverse();\n        }\n\n        return {viewPieceList: viewPieceList, endsText: endsText};\n    },\n\n    /**\n     * @private\n     */\n    _createItemSymbol: function (group, representValue, shapeParam) {\n        group.add(createSymbol(\n            this.getControllerVisual(representValue, 'symbol'),\n            shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3],\n            this.getControllerVisual(representValue, 'color')\n        ));\n    },\n\n    /**\n     * @private\n     */\n    _onItemClick: function (piece) {\n        var visualMapModel = this.visualMapModel;\n        var option = visualMapModel.option;\n        var selected = clone(option.selected);\n        var newKey = visualMapModel.getSelectedMapKey(piece);\n\n        if (option.selectedMode === 'single') {\n            selected[newKey] = true;\n            each$1(selected, function (o, key) {\n                selected[key] = key === newKey;\n            });\n        }\n        else {\n            selected[newKey] = !selected[newKey];\n        }\n\n        this.api.dispatchAction({\n            type: 'selectDataRange',\n            from: this.uid,\n            visualMapId: this.visualMapModel.id,\n            selected: selected\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * visualMap component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar addCommas$1 = addCommas;\nvar encodeHTML$1 = encodeHTML;\n\nfunction fillLabel(opt) {\n    defaultEmphasis(opt, 'label', ['show']);\n}\nvar MarkerModel = extendComponentModel({\n\n    type: 'marker',\n\n    dependencies: ['series', 'grid', 'polar', 'geo'],\n\n    /**\n     * @overrite\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        if (__DEV__) {\n            if (this.type === 'marker') {\n                throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.');\n            }\n        }\n        this.mergeDefaultAndTheme(option, ecModel);\n        this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var hostSeries = this.__hostSeries;\n        return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();\n    },\n\n    mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {\n        var MarkerModel = this.constructor;\n        var modelPropName = this.mainType + 'Model';\n        if (!createdBySelf) {\n            ecModel.eachSeries(function (seriesModel) {\n\n                var markerOpt = seriesModel.get(this.mainType, true);\n\n                var markerModel = seriesModel[modelPropName];\n                if (!markerOpt || !markerOpt.data) {\n                    seriesModel[modelPropName] = null;\n                    return;\n                }\n                if (!markerModel) {\n                    if (isInit) {\n                        // Default label emphasis `position` and `show`\n                        fillLabel(markerOpt);\n                    }\n                    each$1(markerOpt.data, function (item) {\n                        // FIXME Overwrite fillLabel method ?\n                        if (item instanceof Array) {\n                            fillLabel(item[0]);\n                            fillLabel(item[1]);\n                        }\n                        else {\n                            fillLabel(item);\n                        }\n                    });\n\n                    markerModel = new MarkerModel(\n                        markerOpt, this, ecModel\n                    );\n\n                    extend(markerModel, {\n                        mainType: this.mainType,\n                        // Use the same series index and name\n                        seriesIndex: seriesModel.seriesIndex,\n                        name: seriesModel.name,\n                        createdBySelf: true\n                    });\n\n                    markerModel.__hostSeries = seriesModel;\n                }\n                else {\n                    markerModel.mergeOption(markerOpt, ecModel, true);\n                }\n                seriesModel[modelPropName] = markerModel;\n            }, this);\n        }\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? map(value, addCommas$1).join(', ') : addCommas$1(value);\n        var name = data.getName(dataIndex);\n        var html = encodeHTML$1(this.name);\n        if (value != null || name) {\n            html += '<br />';\n        }\n        if (name) {\n            html += encodeHTML$1(name);\n            if (value != null) {\n                html += ' : ';\n            }\n        }\n        if (value != null) {\n            html += encodeHTML$1(formattedValue);\n        }\n        return html;\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    setData: function (data) {\n        this._data = data;\n    }\n});\n\nmixin(MarkerModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markPoint',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n        symbol: 'pin',\n        symbolSize: 50,\n        //symbolRotate: 0,\n        //symbolOffset: [0, 0]\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'inside'\n        },\n        itemStyle: {\n            borderWidth: 2\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar indexOf$2 = indexOf;\n\nfunction hasXOrY(item) {\n    return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));\n}\n\nfunction hasXAndY(item) {\n    return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));\n}\n\n// Make it simple, do not visit all stacked value to count precision.\n// function getPrecision(data, valueAxisDim, dataIndex) {\n//     var precision = -1;\n//     var stackedDim = data.mapDimension(valueAxisDim);\n//     do {\n//         precision = Math.max(\n//             numberUtil.getPrecision(data.get(stackedDim, dataIndex)),\n//             precision\n//         );\n//         var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n//         if (stackedOnSeries) {\n//             var byValue = data.get(data.getCalculationInfo('stackedByDimension'), dataIndex);\n//             data = stackedOnSeries.getData();\n//             dataIndex = data.indexOf(data.getCalculationInfo('stackedByDimension'), byValue);\n//             stackedDim = data.getCalculationInfo('stackedDimension');\n//         }\n//         else {\n//             data = null;\n//         }\n//     } while (data);\n\n//     return precision;\n// }\n\nfunction markerTypeCalculatorWithExtent(\n    mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex\n) {\n    var coordArr = [];\n\n    var stacked = isDimensionStacked(data, targetDataDim /*, otherDataDim*/);\n    var calcDataDim = stacked\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDataDim;\n\n    var value = numCalculate(data, calcDataDim, mlType);\n\n    var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];\n    coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);\n    coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex);\n\n    // Make it simple, do not visit all stacked value to count precision.\n    var precision = getPrecision(data.get(targetDataDim, dataIndex));\n    precision = Math.min(precision, 20);\n    if (precision >= 0) {\n        coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);\n    }\n\n    return coordArr;\n}\n\nvar curry$6 = curry;\n// TODO Specified percent\nvar markerTypeCalculator = {\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    min: curry$6(markerTypeCalculatorWithExtent, 'min'),\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    max: curry$6(markerTypeCalculatorWithExtent, 'max'),\n\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    average: curry$6(markerTypeCalculatorWithExtent, 'average')\n};\n\n/**\n * Transform markPoint data item to format used in List by do the following\n * 1. Calculate statistic like `max`, `min`, `average`\n * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array\n * @param  {module:echarts/model/Series} seriesModel\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {Object}\n */\nfunction dataTransform(seriesModel, item) {\n    var data = seriesModel.getData();\n    var coordSys = seriesModel.coordinateSystem;\n\n    // 1. If not specify the position with pixel directly\n    // 2. If `coord` is not a data array. Which uses `xAxis`,\n    // `yAxis` to specify the coord on each dimension\n\n    // parseFloat first because item.x and item.y can be percent string like '20%'\n    if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) {\n        var dims = coordSys.dimensions;\n        var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n\n        // Clone the option\n        // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value\n        item = clone(item);\n\n        if (item.type\n            && markerTypeCalculator[item.type]\n            && axisInfo.baseAxis && axisInfo.valueAxis\n        ) {\n            var otherCoordIndex = indexOf$2(dims, axisInfo.baseAxis.dim);\n            var targetCoordIndex = indexOf$2(dims, axisInfo.valueAxis.dim);\n\n            item.coord = markerTypeCalculator[item.type](\n                data, axisInfo.baseDataDim, axisInfo.valueDataDim,\n                otherCoordIndex, targetCoordIndex\n            );\n            // Force to use the value of calculated value.\n            item.value = item.coord[targetCoordIndex];\n        }\n        else {\n            // FIXME Only has one of xAxis and yAxis.\n            var coord = [\n                item.xAxis != null ? item.xAxis : item.radiusAxis,\n                item.yAxis != null ? item.yAxis : item.angleAxis\n            ];\n            // Each coord support max, min, average\n            for (var i = 0; i < 2; i++) {\n                if (markerTypeCalculator[coord[i]]) {\n                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);\n                }\n            }\n            item.coord = coord;\n        }\n    }\n    return item;\n}\n\nfunction getAxisInfo$1(item, data, coordSys, seriesModel) {\n    var ret = {};\n\n    if (item.valueIndex != null || item.valueDim != null) {\n        ret.valueDataDim = item.valueIndex != null\n            ? data.getDimension(item.valueIndex) : item.valueDim;\n        ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim));\n        ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n    }\n    else {\n        ret.baseAxis = seriesModel.getBaseAxis();\n        ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n        ret.valueDataDim = data.mapDimension(ret.valueAxis.dim);\n    }\n\n    return ret;\n}\n\nfunction dataDimToCoordDim(seriesModel, dataDim) {\n    var data = seriesModel.getData();\n    var dimensions = data.dimensions;\n    dataDim = data.getDimension(dataDim);\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimItem = data.getDimensionInfo(dimensions[i]);\n        if (dimItem.name === dataDim) {\n            return dimItem.coordDim;\n        }\n    }\n}\n\n/**\n * Filter data which is out of coordinateSystem range\n * [dataFilter description]\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {boolean}\n */\nfunction dataFilter$1(coordSys, item) {\n    // Alwalys return true if there is no coordSys\n    return (coordSys && coordSys.containData && item.coord && !hasXOrY(item))\n        ? coordSys.containData(item.coord) : true;\n}\n\nfunction dimValueGetter(item, dimName, dataIndex, dimIndex) {\n    // x, y, radius, angle\n    if (dimIndex < 2) {\n        return item.coord && item.coord[dimIndex];\n    }\n    return item.value;\n}\n\nfunction numCalculate(data, valueDataDim, type) {\n    if (type === 'average') {\n        var sum = 0;\n        var count = 0;\n        data.each(valueDataDim, function (val, idx) {\n            if (!isNaN(val)) {\n                sum += val;\n                count++;\n            }\n        });\n        return sum / count;\n    }\n    else if (type === 'median') {\n        return data.getMedian(valueDataDim);\n    }\n    else {\n        // max & min\n        return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MarkerView = extendComponentView({\n\n    type: 'marker',\n\n    init: function () {\n        /**\n         * Markline grouped by series\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this.markerGroupMap = createHashMap();\n    },\n\n    render: function (markerModel, ecModel, api) {\n        var markerGroupMap = this.markerGroupMap;\n        markerGroupMap.each(function (item) {\n            item.__keep = false;\n        });\n\n        var markerModelKey = this.type + 'Model';\n        ecModel.eachSeries(function (seriesModel) {\n            var markerModel = seriesModel[markerModelKey];\n            markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api);\n        }, this);\n\n        markerGroupMap.each(function (item) {\n            !item.__keep && this.group.remove(item.group);\n        }, this);\n    },\n\n    renderSeries: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction updateMarkerLayout(mpData, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    mpData.each(function (idx) {\n        var itemModel = mpData.getItemModel(idx);\n        var point;\n        var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n        var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n        if (!isNaN(xPx) && !isNaN(yPx)) {\n            point = [xPx, yPx];\n        }\n        // Chart like bar may have there own marker positioning logic\n        else if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                mpData.getValues(mpData.dimensions, idx)\n            );\n        }\n        else if (coordSys) {\n            var x = mpData.get(coordSys.dimensions[0], idx);\n            var y = mpData.get(coordSys.dimensions[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n\n        mpData.setItemLayout(idx, point);\n    });\n}\n\nMarkerView.extend({\n\n    type: 'markPoint',\n\n    // updateLayout: function (markPointModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mpModel = seriesModel.markPointModel;\n    //         if (mpModel) {\n    //             updateMarkerLayout(mpModel.getData(), seriesModel, api);\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markPointModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mpModel = seriesModel.markPointModel;\n            if (mpModel) {\n                updateMarkerLayout(mpModel.getData(), seriesModel, api);\n                this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mpModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var symbolDrawMap = this.markerGroupMap;\n        var symbolDraw = symbolDrawMap.get(seriesId)\n            || symbolDrawMap.set(seriesId, new SymbolDraw());\n\n        var mpData = createList$1(coordSys, seriesModel, mpModel);\n\n        // FIXME\n        mpModel.setData(mpData);\n\n        updateMarkerLayout(mpModel.getData(), seriesModel, api);\n\n        mpData.each(function (idx) {\n            var itemModel = mpData.getItemModel(idx);\n            var symbolSize = itemModel.getShallow('symbolSize');\n            if (typeof symbolSize === 'function') {\n                // FIXME 这里不兼容 ECharts 2.x，2.x 貌似参数是整个数据？\n                symbolSize = symbolSize(\n                    mpModel.getRawValue(idx), mpModel.getDataParams(idx)\n                );\n            }\n            mpData.setItemVisual(idx, {\n                symbolSize: symbolSize,\n                color: itemModel.get('itemStyle.color')\n                    || seriesData.getVisual('color'),\n                symbol: itemModel.getShallow('symbol')\n            });\n        });\n\n        // TODO Text are wrong\n        symbolDraw.updateData(mpData);\n        this.group.add(symbolDraw.group);\n\n        // Set host model for tooltip\n        // FIXME\n        mpData.eachItemGraphicEl(function (el) {\n            el.traverse(function (child) {\n                child.dataModel = mpModel;\n            });\n        });\n\n        symbolDraw.__keep = true;\n\n        symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} [coordSys]\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$1(coordSys, seriesModel, mpModel) {\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var mpData = new List(coordDimsInfos, mpModel);\n    var dataOpt = map(mpModel.get('data'), curry(\n            dataTransform, seriesModel\n        ));\n    if (coordSys) {\n        dataOpt = filter(\n            dataOpt, curry(dataFilter$1, coordSys)\n        );\n    }\n\n    mpData.initData(dataOpt, null,\n        coordSys ? dimValueGetter : function (item) {\n            return item.value;\n        }\n    );\n\n    return mpData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// HINT Markpoint can't be used too much\nregisterPreprocessor(function (opt) {\n    // Make sure markPoint component is enabled\n    opt.markPoint = opt.markPoint || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markLine',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n\n        symbol: ['circle', 'arrow'],\n        symbolSize: [8, 16],\n\n        //symbolRotate: 0,\n\n        precision: 2,\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'end'\n        },\n        lineStyle: {\n            type: 'dashed'\n        },\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                width: 3\n            }\n        },\n        animationEasing: 'linear'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar markLineTransform = function (seriesModel, coordSys, mlModel, item) {\n    var data = seriesModel.getData();\n    // Special type markLine like 'min', 'max', 'average', 'median'\n    var mlType = item.type;\n\n    if (!isArray(item)\n        && (\n            mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'\n            // In case\n            // data: [{\n            //   yAxis: 10\n            // }]\n            || (item.xAxis != null || item.yAxis != null)\n        )\n    ) {\n        var valueAxis;\n        var valueDataDim;\n        var value;\n\n        if (item.yAxis != null || item.xAxis != null) {\n            valueDataDim = item.yAxis != null ? 'y' : 'x';\n            valueAxis = coordSys.getAxis(valueDataDim);\n\n            value = retrieve(item.yAxis, item.xAxis);\n        }\n        else {\n            var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n            valueDataDim = axisInfo.valueDataDim;\n            valueAxis = axisInfo.valueAxis;\n            value = numCalculate(data, valueDataDim, mlType);\n        }\n        var valueIndex = valueDataDim === 'x' ? 0 : 1;\n        var baseIndex = 1 - valueIndex;\n\n        var mlFrom = clone(item);\n        var mlTo = {};\n\n        mlFrom.type = null;\n\n        mlFrom.coord = [];\n        mlTo.coord = [];\n        mlFrom.coord[baseIndex] = -Infinity;\n        mlTo.coord[baseIndex] = Infinity;\n\n        var precision = mlModel.get('precision');\n        if (precision >= 0 && typeof value === 'number') {\n            value = +value.toFixed(Math.min(precision, 20));\n        }\n\n        mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;\n\n        item = [mlFrom, mlTo, { // Extra option for tooltip and label\n            type: mlType,\n            valueIndex: item.valueIndex,\n            // Force to use the value of calculated value.\n            value: value\n        }];\n    }\n\n    item = [\n        dataTransform(seriesModel, item[0]),\n        dataTransform(seriesModel, item[1]),\n        extend({}, item[2])\n    ];\n\n    // Avoid line data type is extended by from(to) data type\n    item[2].type = item[2].type || '';\n\n    // Merge from option and to option into line option\n    merge(item[2], item[0]);\n    merge(item[2], item[1]);\n\n    return item;\n};\n\nfunction isInifinity(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markLine has one dim\nfunction ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    var dimName = coordSys.dimensions[dimIndex];\n    return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])\n        && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);\n}\n\nfunction markLineFilter(coordSys, item) {\n    if (coordSys.type === 'cartesian2d') {\n        var fromCoord = item[0].coord;\n        var toCoord = item[1].coord;\n        // In case\n        // {\n        //  markLine: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, item[0])\n        && dataFilter$1(coordSys, item[1]);\n}\n\nfunction updateSingleMarkerEndLayout(\n    data, idx, isFrom, seriesModel, api\n) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(data.dimensions, idx)\n            );\n        }\n        else {\n            var dims = coordSys.dimensions;\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n        }\n        // Expand line to the edge of grid if value on one axis is Inifnity\n        // In case\n        //  markLine: {\n        //    data: [{\n        //      yAxis: 2\n        //      // or\n        //      type: 'average'\n        //    }]\n        //  }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var dims = coordSys.dimensions;\n            if (isInifinity(data.get(dims[0], idx))) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n            else if (isInifinity(data.get(dims[1], idx))) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    data.setItemLayout(idx, point);\n}\n\nMarkerView.extend({\n\n    type: 'markLine',\n\n    // updateLayout: function (markLineModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mlModel = seriesModel.markLineModel;\n    //         if (mlModel) {\n    //             var mlData = mlModel.getData();\n    //             var fromData = mlModel.__from;\n    //             var toData = mlModel.__to;\n    //             // Update visual and layout of from symbol and to symbol\n    //             fromData.each(function (idx) {\n    //                 updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n    //                 updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n    //             });\n    //             // Update layout of line\n    //             mlData.each(function (idx) {\n    //                 mlData.setItemLayout(idx, [\n    //                     fromData.getItemLayout(idx),\n    //                     toData.getItemLayout(idx)\n    //                 ]);\n    //             });\n\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markLineModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mlModel = seriesModel.markLineModel;\n            if (mlModel) {\n                var mlData = mlModel.getData();\n                var fromData = mlModel.__from;\n                var toData = mlModel.__to;\n                // Update visual and layout of from symbol and to symbol\n                fromData.each(function (idx) {\n                    updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n                    updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n                });\n                // Update layout of line\n                mlData.each(function (idx) {\n                    mlData.setItemLayout(idx, [\n                        fromData.getItemLayout(idx),\n                        toData.getItemLayout(idx)\n                    ]);\n                });\n\n                this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mlModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var lineDrawMap = this.markerGroupMap;\n        var lineDraw = lineDrawMap.get(seriesId)\n            || lineDrawMap.set(seriesId, new LineDraw());\n        this.group.add(lineDraw.group);\n\n        var mlData = createList$2(coordSys, seriesModel, mlModel);\n\n        var fromData = mlData.from;\n        var toData = mlData.to;\n        var lineData = mlData.line;\n\n        mlModel.__from = fromData;\n        mlModel.__to = toData;\n        // Line data for tooltip and formatter\n        mlModel.setData(lineData);\n\n        var symbolType = mlModel.get('symbol');\n        var symbolSize = mlModel.get('symbolSize');\n        if (!isArray(symbolType)) {\n            symbolType = [symbolType, symbolType];\n        }\n        if (typeof symbolSize === 'number') {\n            symbolSize = [symbolSize, symbolSize];\n        }\n\n        // Update visual and layout of from symbol and to symbol\n        mlData.from.each(function (idx) {\n            updateDataVisualAndLayout(fromData, idx, true);\n            updateDataVisualAndLayout(toData, idx, false);\n        });\n\n        // Update visual and layout of line\n        lineData.each(function (idx) {\n            var lineColor = lineData.getItemModel(idx).get('lineStyle.color');\n            lineData.setItemVisual(idx, {\n                color: lineColor || fromData.getItemVisual(idx, 'color')\n            });\n            lineData.setItemLayout(idx, [\n                fromData.getItemLayout(idx),\n                toData.getItemLayout(idx)\n            ]);\n\n            lineData.setItemVisual(idx, {\n                'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),\n                'fromSymbol': fromData.getItemVisual(idx, 'symbol'),\n                'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),\n                'toSymbol': toData.getItemVisual(idx, 'symbol')\n            });\n        });\n\n        lineDraw.updateData(lineData);\n\n        // Set host model for tooltip\n        // FIXME\n        mlData.line.eachItemGraphicEl(function (el, idx) {\n            el.traverse(function (child) {\n                child.dataModel = mlModel;\n            });\n        });\n\n        function updateDataVisualAndLayout(data, idx, isFrom) {\n            var itemModel = data.getItemModel(idx);\n\n            updateSingleMarkerEndLayout(\n                data, idx, isFrom, seriesModel, api\n            );\n\n            data.setItemVisual(idx, {\n                symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],\n                symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],\n                color: itemModel.get('itemStyle.color') || seriesData.getVisual('color')\n            });\n        }\n\n        lineDraw.__keep = true;\n\n        lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$2(coordSys, seriesModel, mlModel) {\n\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var fromData = new List(coordDimsInfos, mlModel);\n    var toData = new List(coordDimsInfos, mlModel);\n    // No dimensions\n    var lineData = new List([], mlModel);\n\n    var optData = map(mlModel.get('data'), curry(\n        markLineTransform, seriesModel, coordSys, mlModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markLineFilter, coordSys)\n        );\n    }\n    var dimValueGetter$$1 = coordSys ? dimValueGetter : function (item) {\n        return item.value;\n    };\n    fromData.initData(\n        map(optData, function (item) {\n            return item[0];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    toData.initData(\n        map(optData, function (item) {\n            return item[1];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    lineData.initData(\n        map(optData, function (item) {\n            return item[2];\n        })\n    );\n    lineData.hasItemOption = true;\n\n    return {\n        from: fromData,\n        to: toData,\n        line: lineData\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markLine component is enabled\n    opt.markLine = opt.markLine || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markArea',\n\n    defaultOption: {\n        zlevel: 0,\n        // PENDING\n        z: 1,\n        tooltip: {\n            trigger: 'item'\n        },\n        // markArea should fixed on the coordinate system\n        animation: false,\n        label: {\n            show: true,\n            position: 'top'\n        },\n        itemStyle: {\n            // color and borderColor default to use color from series\n            // color: 'auto'\n            // borderColor: 'auto'\n            borderWidth: 0\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                position: 'top'\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Better on polar\n\nvar markAreaTransform = function (seriesModel, coordSys, maModel, item) {\n    var lt = dataTransform(seriesModel, item[0]);\n    var rb = dataTransform(seriesModel, item[1]);\n    var retrieve$$1 = retrieve;\n\n    // FIXME make sure lt is less than rb\n    var ltCoord = lt.coord;\n    var rbCoord = rb.coord;\n    ltCoord[0] = retrieve$$1(ltCoord[0], -Infinity);\n    ltCoord[1] = retrieve$$1(ltCoord[1], -Infinity);\n\n    rbCoord[0] = retrieve$$1(rbCoord[0], Infinity);\n    rbCoord[1] = retrieve$$1(rbCoord[1], Infinity);\n\n    // Merge option into one\n    var result = mergeAll([{}, lt, rb]);\n\n    result.coord = [\n        lt.coord, rb.coord\n    ];\n    result.x0 = lt.x;\n    result.y0 = lt.y;\n    result.x1 = rb.x;\n    result.y1 = rb.y;\n    return result;\n};\n\nfunction isInifinity$1(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markArea has one dim\nfunction ifMarkLineHasOnlyDim$1(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    return isInifinity$1(fromCoord[otherDimIndex]) && isInifinity$1(toCoord[otherDimIndex]);\n}\n\nfunction markAreaFilter(coordSys, item) {\n    var fromCoord = item.coord[0];\n    var toCoord = item.coord[1];\n    if (coordSys.type === 'cartesian2d') {\n        // In case\n        // {\n        //  markArea: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim$1(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim$1(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, {\n            coord: fromCoord,\n            x: item.x0,\n            y: item.y0\n        })\n        || dataFilter$1(coordSys, {\n            coord: toCoord,\n            x: item.x1,\n            y: item.y1\n        });\n}\n\n// dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']\nfunction getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get(dims[0]), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get(dims[1]), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(dims, idx)\n            );\n        }\n        else {\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            var pt = [x, y];\n            coordSys.clampData && coordSys.clampData(pt, pt);\n            point = coordSys.dataToPoint(pt, true);\n        }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            if (isInifinity$1(x)) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);\n            }\n            else if (isInifinity$1(y)) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    return point;\n}\n\nvar dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];\n\nMarkerView.extend({\n\n    type: 'markArea',\n\n    // updateLayout: function (markAreaModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var maModel = seriesModel.markAreaModel;\n    //         if (maModel) {\n    //             var areaData = maModel.getData();\n    //             areaData.each(function (idx) {\n    //                 var points = zrUtil.map(dimPermutations, function (dim) {\n    //                     return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n    //                 });\n    //                 // Layout\n    //                 areaData.setItemLayout(idx, points);\n    //                 var el = areaData.getItemGraphicEl(idx);\n    //                 el.setShape('points', points);\n    //             });\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markAreaModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var maModel = seriesModel.markAreaModel;\n            if (maModel) {\n                var areaData = maModel.getData();\n                areaData.each(function (idx) {\n                    var points = map(dimPermutations, function (dim) {\n                        return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n                    });\n                    // Layout\n                    areaData.setItemLayout(idx, points);\n                    var el = areaData.getItemGraphicEl(idx);\n                    el.setShape('points', points);\n                });\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, maModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var areaGroupMap = this.markerGroupMap;\n        var polygonGroup = areaGroupMap.get(seriesId)\n            || areaGroupMap.set(seriesId, {group: new Group()});\n\n        this.group.add(polygonGroup.group);\n        polygonGroup.__keep = true;\n\n        var areaData = createList$3(coordSys, seriesModel, maModel);\n\n        // Line data for tooltip and formatter\n        maModel.setData(areaData);\n\n        // Update visual and layout of line\n        areaData.each(function (idx) {\n            // Layout\n            areaData.setItemLayout(idx, map(dimPermutations, function (dim) {\n                return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n            }));\n\n            // Visual\n            areaData.setItemVisual(idx, {\n                color: seriesData.getVisual('color')\n            });\n        });\n\n\n        areaData.diff(polygonGroup.__data)\n            .add(function (idx) {\n                var polygon = new Polygon({\n                    shape: {\n                        points: areaData.getItemLayout(idx)\n                    }\n                });\n                areaData.setItemGraphicEl(idx, polygon);\n                polygonGroup.group.add(polygon);\n            })\n            .update(function (newIdx, oldIdx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx);\n                updateProps(polygon, {\n                    shape: {\n                        points: areaData.getItemLayout(newIdx)\n                    }\n                }, maModel, newIdx);\n                polygonGroup.group.add(polygon);\n                areaData.setItemGraphicEl(newIdx, polygon);\n            })\n            .remove(function (idx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(idx);\n                polygonGroup.group.remove(polygon);\n            })\n            .execute();\n\n        areaData.eachItemGraphicEl(function (polygon, idx) {\n            var itemModel = areaData.getItemModel(idx);\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            var color = areaData.getItemVisual(idx, 'color');\n            polygon.useStyle(\n                defaults(\n                    itemModel.getModel('itemStyle').getItemStyle(),\n                    {\n                        fill: modifyAlpha(color, 0.4),\n                        stroke: color\n                    }\n                )\n            );\n\n            polygon.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                polygon.style, polygon.hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: maModel,\n                    labelDataIndex: idx,\n                    defaultText: areaData.getName(idx) || '',\n                    isRectText: true,\n                    autoColor: color\n                }\n            );\n\n            setHoverStyle(polygon, {});\n\n            polygon.dataModel = maModel;\n        });\n\n        polygonGroup.__data = areaData;\n\n        polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$3(coordSys, seriesModel, maModel) {\n\n    var coordDimsInfos;\n    var areaData;\n    var dims = ['x0', 'y0', 'x1', 'y1'];\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var data = seriesModel.getData();\n            var info = data.getDimensionInfo(\n                data.mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n        areaData = new List(map(dims, function (dim, idx) {\n            return {\n                name: dim,\n                type: coordDimsInfos[idx % 2].type\n            };\n        }), maModel);\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n        areaData = new List(coordDimsInfos, maModel);\n    }\n\n    var optData = map(maModel.get('data'), curry(\n        markAreaTransform, seriesModel, coordSys, maModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markAreaFilter, coordSys)\n        );\n    }\n\n    var dimValueGetter$$1 = coordSys ? function (item, dimName, dataIndex, dimIndex) {\n        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];\n    } : function (item) {\n        return item.value;\n    };\n    areaData.initData(optData, null, dimValueGetter$$1);\n    areaData.hasItemOption = true;\n    return areaData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markArea component is enabled\n    opt.markArea = opt.markArea || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar preprocessor$3 = function (option) {\n    var timelineOpt = option && option.timeline;\n\n    if (!isArray(timelineOpt)) {\n        timelineOpt = timelineOpt ? [timelineOpt] : [];\n    }\n\n    each$1(timelineOpt, function (opt) {\n        if (!opt) {\n            return;\n        }\n\n        compatibleEC2(opt);\n    });\n};\n\nfunction compatibleEC2(opt) {\n    var type = opt.type;\n\n    var ec2Types = {'number': 'value', 'time': 'time'};\n\n    // Compatible with ec2\n    if (ec2Types[type]) {\n        opt.axisType = ec2Types[type];\n        delete opt.type;\n    }\n\n    transferItem(opt);\n\n    if (has$2(opt, 'controlPosition')) {\n        var controlStyle = opt.controlStyle || (opt.controlStyle = {});\n        if (!has$2(controlStyle, 'position')) {\n            controlStyle.position = opt.controlPosition;\n        }\n        if (controlStyle.position === 'none' && !has$2(controlStyle, 'show')) {\n            controlStyle.show = false;\n            delete controlStyle.position;\n        }\n        delete opt.controlPosition;\n    }\n\n    each$1(opt.data || [], function (dataItem) {\n        if (isObject$1(dataItem) && !isArray(dataItem)) {\n            if (!has$2(dataItem, 'value') && has$2(dataItem, 'name')) {\n                // In ec2, using name as value.\n                dataItem.value = dataItem.name;\n            }\n            transferItem(dataItem);\n        }\n    });\n}\n\nfunction transferItem(opt) {\n    var itemStyle = opt.itemStyle || (opt.itemStyle = {});\n\n    var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {});\n\n    // Transfer label out\n    var label = opt.label || (opt.label || {});\n    var labelNormal = label.normal || (label.normal = {});\n    var excludeLabelAttr = {normal: 1, emphasis: 1};\n\n    each$1(label, function (value, name) {\n        if (!excludeLabelAttr[name] && !has$2(labelNormal, name)) {\n            labelNormal[name] = value;\n        }\n    });\n\n    if (itemStyleEmphasis.label && !has$2(label, 'emphasis')) {\n        label.emphasis = itemStyleEmphasis.label;\n        delete itemStyleEmphasis.label;\n    }\n}\n\nfunction has$2(obj, attr) {\n    return obj.hasOwnProperty(attr);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('timeline', function () {\n    // Only slider now.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction(\n\n    {type: 'timelineChange', event: 'timelineChanged', update: 'prepareAndUpdate'},\n\n    function (payload, ecModel) {\n\n        var timelineModel = ecModel.getComponent('timeline');\n        if (timelineModel && payload.currentIndex != null) {\n            timelineModel.setCurrentIndex(payload.currentIndex);\n\n            if (!timelineModel.get('loop', true) && timelineModel.isIndexMax()) {\n                timelineModel.setPlayState(false);\n            }\n        }\n\n        // Set normalized currentIndex to payload.\n        ecModel.resetOption('timeline');\n\n        return defaults({\n            currentIndex: timelineModel.option.currentIndex\n        }, payload);\n    }\n);\n\nregisterAction(\n\n    {type: 'timelinePlayChange', event: 'timelinePlayChanged', update: 'update'},\n\n    function (payload, ecModel) {\n        var timelineModel = ecModel.getComponent('timeline');\n        if (timelineModel && payload.playState != null) {\n            timelineModel.setPlayState(payload.playState);\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TimelineModel = ComponentModel.extend({\n\n    type: 'timeline',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        zlevel: 0,                  // 一级层叠\n        z: 4,                       // 二级层叠\n        show: true,\n\n        axisType: 'time',  // 模式是时间类型，支持 value, category\n\n        realtime: true,\n\n        left: '20%',\n        top: null,\n        right: '20%',\n        bottom: 0,\n        width: null,\n        height: 40,\n        padding: 5,\n\n        controlPosition: 'left',           // 'left' 'right' 'top' 'bottom' 'none'\n        autoPlay: false,\n        rewind: false,                     // 反向播放\n        loop: true,\n        playInterval: 2000,                // 播放时间间隔，单位ms\n\n        currentIndex: 0,\n\n        itemStyle: {},\n        label: {\n            color: '#000'\n        },\n\n        data: []\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * @private\n         * @type {module:echarts/data/List}\n         */\n        this._data;\n\n        /**\n         * @private\n         * @type {Array.<string>}\n         */\n        this._names;\n\n        this.mergeDefaultAndTheme(option, ecModel);\n        this._initData();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        TimelineModel.superApply(this, 'mergeOption', arguments);\n        this._initData();\n    },\n\n    /**\n     * @param {number} [currentIndex]\n     */\n    setCurrentIndex: function (currentIndex) {\n        if (currentIndex == null) {\n            currentIndex = this.option.currentIndex;\n        }\n        var count = this._data.count();\n\n        if (this.option.loop) {\n            currentIndex = (currentIndex % count + count) % count;\n        }\n        else {\n            currentIndex >= count && (currentIndex = count - 1);\n            currentIndex < 0 && (currentIndex = 0);\n        }\n\n        this.option.currentIndex = currentIndex;\n    },\n\n    /**\n     * @return {number} currentIndex\n     */\n    getCurrentIndex: function () {\n        return this.option.currentIndex;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isIndexMax: function () {\n        return this.getCurrentIndex() >= this._data.count() - 1;\n    },\n\n    /**\n     * @param {boolean} state true: play, false: stop\n     */\n    setPlayState: function (state) {\n        this.option.autoPlay = !!state;\n    },\n\n    /**\n     * @return {boolean} true: play, false: stop\n     */\n    getPlayState: function () {\n        return !!this.option.autoPlay;\n    },\n\n    /**\n     * @private\n     */\n    _initData: function () {\n        var thisOption = this.option;\n        var dataArr = thisOption.data || [];\n        var axisType = thisOption.axisType;\n        var names = this._names = [];\n\n        if (axisType === 'category') {\n            var idxArr = [];\n            each$1(dataArr, function (item, index) {\n                var value = getDataItemValue(item);\n                var newItem;\n\n                if (isObject$1(item)) {\n                    newItem = clone(item);\n                    newItem.value = index;\n                }\n                else {\n                    newItem = index;\n                }\n\n                idxArr.push(newItem);\n\n                if (!isString(value) && (value == null || isNaN(value))) {\n                    value = '';\n                }\n\n                names.push(value + '');\n            });\n            dataArr = idxArr;\n        }\n\n        var dimType = ({category: 'ordinal', time: 'time'})[axisType] || 'number';\n\n        var data = this._data = new List([{name: 'value', type: dimType}], this);\n\n        data.initData(dataArr, names);\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @public\n     * @return {Array.<string>} categoreis\n     */\n    getCategories: function () {\n        if (this.get('axisType') === 'category') {\n            return this._names.slice();\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderTimelineModel = TimelineModel.extend({\n\n    type: 'timeline.slider',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        backgroundColor: 'rgba(0,0,0,0)',   // 时间轴背景颜色\n        borderColor: '#ccc',               // 时间轴边框颜色\n        borderWidth: 0,                    // 时间轴边框线宽，单位px，默认为0（无边框）\n\n        orient: 'horizontal',              // 'vertical'\n        inverse: false,\n\n        tooltip: {                          // boolean or Object\n            trigger: 'item'                 // data item may also have tootip attr.\n        },\n\n        symbol: 'emptyCircle',\n        symbolSize: 10,\n\n        lineStyle: {\n            show: true,\n            width: 2,\n            color: '#304654'\n        },\n        label: {                            // 文本标签\n            position: 'auto',           // auto left right top bottom\n                                        // When using number, label position is not\n                                        // restricted by viewRect.\n                                        // positive: right/bottom, negative: left/top\n            show: true,\n            interval: 'auto',\n            rotate: 0,\n            // formatter: null,\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: '#304654'\n        },\n        itemStyle: {\n            color: '#304654',\n            borderWidth: 1\n        },\n\n        checkpointStyle: {\n            symbol: 'circle',\n            symbolSize: 13,\n            color: '#c23531',\n            borderWidth: 5,\n            borderColor: 'rgba(194,53,49, 0.5)',\n            animation: true,\n            animationDuration: 300,\n            animationEasing: 'quinticInOut'\n        },\n\n        controlStyle: {\n            show: true,\n            showPlayBtn: true,\n            showPrevBtn: true,\n            showNextBtn: true,\n            itemSize: 22,\n            itemGap: 12,\n            position: 'left',  // 'left' 'right' 'top' 'bottom'\n            playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', // jshint ignore:line\n            stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', // jshint ignore:line\n            nextIcon: 'path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z', // jshint ignore:line\n            prevIcon: 'path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z', // jshint ignore:line\n\n            color: '#304654',\n            borderColor: '#304654',\n            borderWidth: 1\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n                color: '#c23531'\n            },\n\n            itemStyle: {\n                color: '#c23531'\n            },\n\n            controlStyle: {\n                color: '#c23531',\n                borderColor: '#c23531',\n                borderWidth: 2\n            }\n        },\n        data: []\n    }\n\n});\n\nmixin(SliderTimelineModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TimelineView = Component.extend({\n    type: 'timeline'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar TimelineAxis = function (dim, scale, coordExtent, axisType) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis model\n     * @param {module:echarts/component/TimelineModel}\n     */\n    this.model = null;\n};\n\nTimelineAxis.prototype = {\n\n    constructor: TimelineAxis,\n\n    /**\n     * @override\n     */\n    getLabelModel: function () {\n        return this.model.getModel('label');\n    },\n\n    /**\n     * @override\n     */\n    isHorizontal: function () {\n        return this.model.get('orient') === 'horizontal';\n    }\n\n};\n\ninherits(TimelineAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$6 = bind;\nvar each$27 = each$1;\n\nvar PI$4 = Math.PI;\n\nTimelineView.extend({\n\n    type: 'timeline.slider',\n\n    init: function (ecModel, api) {\n\n        this.api = api;\n\n        /**\n         * @private\n         * @type {module:echarts/component/timeline/TimelineAxis}\n         */\n        this._axis;\n\n        /**\n         * @private\n         * @type {module:zrender/core/BoundingRect}\n         */\n        this._viewRect;\n\n        /**\n         * @type {number}\n         */\n        this._timer;\n\n        /**\n         * @type {module:zrender/Element}\n         */\n        this._currentPointer;\n\n        /**\n         * @type {module:zrender/container/Group}\n         */\n        this._mainGroup;\n\n        /**\n         * @type {module:zrender/container/Group}\n         */\n        this._labelGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (timelineModel, ecModel, api, payload) {\n        this.model = timelineModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        this.group.removeAll();\n\n        if (timelineModel.get('show', true)) {\n\n            var layoutInfo = this._layout(timelineModel, api);\n            var mainGroup = this._createGroup('mainGroup');\n            var labelGroup = this._createGroup('labelGroup');\n\n            /**\n             * @private\n             * @type {module:echarts/component/timeline/TimelineAxis}\n             */\n            var axis = this._axis = this._createAxis(layoutInfo, timelineModel);\n\n            timelineModel.formatTooltip = function (dataIndex) {\n                return encodeHTML(axis.scale.getLabel(dataIndex));\n            };\n\n            each$27(\n                ['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'],\n                function (name) {\n                    this['_render' + name](layoutInfo, mainGroup, axis, timelineModel);\n                },\n                this\n            );\n\n            this._renderAxisLabel(layoutInfo, labelGroup, axis, timelineModel);\n            this._position(layoutInfo, timelineModel);\n        }\n\n        this._doPlayStop();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearTimer();\n        this.group.removeAll();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clearTimer();\n    },\n\n    _layout: function (timelineModel, api) {\n        var labelPosOpt = timelineModel.get('label.position');\n        var orient = timelineModel.get('orient');\n        var viewRect = getViewRect$4(timelineModel, api);\n        // Auto label offset.\n        if (labelPosOpt == null || labelPosOpt === 'auto') {\n            labelPosOpt = orient === 'horizontal'\n                ? ((viewRect.y + viewRect.height / 2) < api.getHeight() / 2 ? '-' : '+')\n                : ((viewRect.x + viewRect.width / 2) < api.getWidth() / 2 ? '+' : '-');\n        }\n        else if (isNaN(labelPosOpt)) {\n            labelPosOpt = ({\n                horizontal: {top: '-', bottom: '+'},\n                vertical: {left: '-', right: '+'}\n            })[orient][labelPosOpt];\n        }\n\n        var labelAlignMap = {\n            horizontal: 'center',\n            vertical: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'left' : 'right'\n        };\n\n        var labelBaselineMap = {\n            horizontal: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'top' : 'bottom',\n            vertical: 'middle'\n        };\n        var rotationMap = {\n            horizontal: 0,\n            vertical: PI$4 / 2\n        };\n\n        // Position\n        var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width;\n\n        var controlModel = timelineModel.getModel('controlStyle');\n        var showControl = controlModel.get('show', true);\n        var controlSize = showControl ? controlModel.get('itemSize') : 0;\n        var controlGap = showControl ? controlModel.get('itemGap') : 0;\n        var sizePlusGap = controlSize + controlGap;\n\n        // Special label rotate.\n        var labelRotation = timelineModel.get('label.rotate') || 0;\n        labelRotation = labelRotation * PI$4 / 180; // To radian.\n\n        var playPosition;\n        var prevBtnPosition;\n        var nextBtnPosition;\n        var axisExtent;\n        var controlPosition = controlModel.get('position', true);\n        var showPlayBtn = showControl && controlModel.get('showPlayBtn', true);\n        var showPrevBtn = showControl && controlModel.get('showPrevBtn', true);\n        var showNextBtn = showControl && controlModel.get('showNextBtn', true);\n        var xLeft = 0;\n        var xRight = mainLength;\n\n        // position[0] means left, position[1] means middle.\n        if (controlPosition === 'left' || controlPosition === 'bottom') {\n            showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap);\n            showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap);\n            showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n        }\n        else { // 'top' 'right'\n            showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n            showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap);\n            showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n        }\n        axisExtent = [xLeft, xRight];\n\n        if (timelineModel.get('inverse')) {\n            axisExtent.reverse();\n        }\n\n        return {\n            viewRect: viewRect,\n            mainLength: mainLength,\n            orient: orient,\n\n            rotation: rotationMap[orient],\n            labelRotation: labelRotation,\n            labelPosOpt: labelPosOpt,\n            labelAlign: timelineModel.get('label.align') || labelAlignMap[orient],\n            labelBaseline: timelineModel.get('label.verticalAlign')\n                || timelineModel.get('label.baseline')\n                || labelBaselineMap[orient],\n\n            // Based on mainGroup.\n            playPosition: playPosition,\n            prevBtnPosition: prevBtnPosition,\n            nextBtnPosition: nextBtnPosition,\n            axisExtent: axisExtent,\n\n            controlSize: controlSize,\n            controlGap: controlGap\n        };\n    },\n\n    _position: function (layoutInfo, timelineModel) {\n        // Position is be called finally, because bounding rect is needed for\n        // adapt content to fill viewRect (auto adapt offset).\n\n        // Timeline may be not all in the viewRect when 'offset' is specified\n        // as a number, because it is more appropriate that label aligns at\n        // 'offset' but not the other edge defined by viewRect.\n\n        var mainGroup = this._mainGroup;\n        var labelGroup = this._labelGroup;\n\n        var viewRect = layoutInfo.viewRect;\n        if (layoutInfo.orient === 'vertical') {\n            // transform to horizontal, inverse rotate by left-top point.\n            var m = create$1();\n            var rotateOriginX = viewRect.x;\n            var rotateOriginY = viewRect.y + viewRect.height;\n            translate(m, m, [-rotateOriginX, -rotateOriginY]);\n            rotate(m, m, -PI$4 / 2);\n            translate(m, m, [rotateOriginX, rotateOriginY]);\n            viewRect = viewRect.clone();\n            viewRect.applyTransform(m);\n        }\n\n        var viewBound = getBound(viewRect);\n        var mainBound = getBound(mainGroup.getBoundingRect());\n        var labelBound = getBound(labelGroup.getBoundingRect());\n\n        var mainPosition = mainGroup.position;\n        var labelsPosition = labelGroup.position;\n\n        labelsPosition[0] = mainPosition[0] = viewBound[0][0];\n\n        var labelPosOpt = layoutInfo.labelPosOpt;\n\n        if (isNaN(labelPosOpt)) { // '+' or '-'\n            var mainBoundIdx = labelPosOpt === '+' ? 0 : 1;\n            toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);\n            toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);\n        }\n        else {\n            var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;\n            toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);\n            labelsPosition[1] = mainPosition[1] + labelPosOpt;\n        }\n\n        mainGroup.attr('position', mainPosition);\n        labelGroup.attr('position', labelsPosition);\n        mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation;\n\n        setOrigin(mainGroup);\n        setOrigin(labelGroup);\n\n        function setOrigin(targetGroup) {\n            var pos = targetGroup.position;\n            targetGroup.origin = [\n                viewBound[0][0] - pos[0],\n                viewBound[1][0] - pos[1]\n            ];\n        }\n\n        function getBound(rect) {\n            // [[xmin, xmax], [ymin, ymax]]\n            return [\n                [rect.x, rect.x + rect.width],\n                [rect.y, rect.y + rect.height]\n            ];\n        }\n\n        function toBound(fromPos, from, to, dimIdx, boundIdx) {\n            fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx];\n        }\n    },\n\n    _createAxis: function (layoutInfo, timelineModel) {\n        var data = timelineModel.getData();\n        var axisType = timelineModel.get('axisType');\n\n        var scale = createScaleByModel(timelineModel, axisType);\n\n        // Customize scale. The `tickValue` is `dataIndex`.\n        scale.getTicks = function () {\n            return data.mapArray(['value'], function (value) {\n                return value;\n            });\n        };\n\n        var dataExtent = data.getDataExtent('value');\n        scale.setExtent(dataExtent[0], dataExtent[1]);\n        scale.niceTicks();\n\n        var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType);\n        axis.model = timelineModel;\n\n        return axis;\n    },\n\n    _createGroup: function (name) {\n        var newGroup = this['_' + name] = new Group();\n        this.group.add(newGroup);\n        return newGroup;\n    },\n\n    _renderAxisLine: function (layoutInfo, group, axis, timelineModel) {\n        var axisExtent = axis.getExtent();\n\n        if (!timelineModel.get('lineStyle.show')) {\n            return;\n        }\n\n        group.add(new Line({\n            shape: {\n                x1: axisExtent[0], y1: 0,\n                x2: axisExtent[1], y2: 0\n            },\n            style: extend(\n                {lineCap: 'round'},\n                timelineModel.getModel('lineStyle').getLineStyle()\n            ),\n            silent: true,\n            z2: 1\n        }));\n    },\n\n    /**\n     * @private\n     */\n    _renderAxisTick: function (layoutInfo, group, axis, timelineModel) {\n        var data = timelineModel.getData();\n        // Show all ticks, despite ignoring strategy.\n        var ticks = axis.scale.getTicks();\n\n        // The value is dataIndex, see the costomized scale.\n        each$27(ticks, function (value) {\n            var tickCoord = axis.dataToCoord(value);\n            var itemModel = data.getItemModel(value);\n            var itemStyleModel = itemModel.getModel('itemStyle');\n            var hoverStyleModel = itemModel.getModel('emphasis.itemStyle');\n            var symbolOpt = {\n                position: [tickCoord, 0],\n                onclick: bind$6(this._changeTimeline, this, value)\n            };\n            var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);\n            setHoverStyle(el, hoverStyleModel.getItemStyle());\n\n            if (itemModel.get('tooltip')) {\n                el.dataIndex = value;\n                el.dataModel = timelineModel;\n            }\n            else {\n                el.dataIndex = el.dataModel = null;\n            }\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderAxisLabel: function (layoutInfo, group, axis, timelineModel) {\n        var labelModel = axis.getLabelModel();\n\n        if (!labelModel.get('show')) {\n            return;\n        }\n\n        var data = timelineModel.getData();\n        var labels = axis.getViewLabels();\n\n        each$27(labels, function (labelItem) {\n            // The tickValue is dataIndex, see the costomized scale.\n            var dataIndex = labelItem.tickValue;\n\n            var itemModel = data.getItemModel(dataIndex);\n            var normalLabelModel = itemModel.getModel('label');\n            var hoverLabelModel = itemModel.getModel('emphasis.label');\n            var tickCoord = axis.dataToCoord(labelItem.tickValue);\n            var textEl = new Text({\n                position: [tickCoord, 0],\n                rotation: layoutInfo.labelRotation - layoutInfo.rotation,\n                onclick: bind$6(this._changeTimeline, this, dataIndex),\n                silent: false\n            });\n            setTextStyle(textEl.style, normalLabelModel, {\n                text: labelItem.formattedLabel,\n                textAlign: layoutInfo.labelAlign,\n                textVerticalAlign: layoutInfo.labelBaseline\n            });\n\n            group.add(textEl);\n            setHoverStyle(\n                textEl, setTextStyle({}, hoverLabelModel)\n            );\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderControl: function (layoutInfo, group, axis, timelineModel) {\n        var controlSize = layoutInfo.controlSize;\n        var rotation = layoutInfo.rotation;\n\n        var itemStyle = timelineModel.getModel('controlStyle').getItemStyle();\n        var hoverStyle = timelineModel.getModel('emphasis.controlStyle').getItemStyle();\n        var rect = [0, -controlSize / 2, controlSize, controlSize];\n        var playState = timelineModel.getPlayState();\n        var inverse = timelineModel.get('inverse', true);\n\n        makeBtn(\n            layoutInfo.nextBtnPosition,\n            'controlStyle.nextIcon',\n            bind$6(this._changeTimeline, this, inverse ? '-' : '+')\n        );\n        makeBtn(\n            layoutInfo.prevBtnPosition,\n            'controlStyle.prevIcon',\n            bind$6(this._changeTimeline, this, inverse ? '+' : '-')\n        );\n        makeBtn(\n            layoutInfo.playPosition,\n            'controlStyle.' + (playState ? 'stopIcon' : 'playIcon'),\n            bind$6(this._handlePlayClick, this, !playState),\n            true\n        );\n\n        function makeBtn(position, iconPath, onclick, willRotate) {\n            if (!position) {\n                return;\n            }\n            var opt = {\n                position: position,\n                origin: [controlSize / 2, 0],\n                rotation: willRotate ? -rotation : 0,\n                rectHover: true,\n                style: itemStyle,\n                onclick: onclick\n            };\n            var btn = makeIcon(timelineModel, iconPath, rect, opt);\n            group.add(btn);\n            setHoverStyle(btn, hoverStyle);\n        }\n    },\n\n    _renderCurrentPointer: function (layoutInfo, group, axis, timelineModel) {\n        var data = timelineModel.getData();\n        var currentIndex = timelineModel.getCurrentIndex();\n        var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle');\n        var me = this;\n\n        var callback = {\n            onCreate: function (pointer) {\n                pointer.draggable = true;\n                pointer.drift = bind$6(me._handlePointerDrag, me);\n                pointer.ondragend = bind$6(me._handlePointerDragend, me);\n                pointerMoveTo(pointer, currentIndex, axis, timelineModel, true);\n            },\n            onUpdate: function (pointer) {\n                pointerMoveTo(pointer, currentIndex, axis, timelineModel);\n            }\n        };\n\n        // Reuse when exists, for animation and drag.\n        this._currentPointer = giveSymbol(\n            pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback\n        );\n    },\n\n    _handlePlayClick: function (nextState) {\n        this._clearTimer();\n        this.api.dispatchAction({\n            type: 'timelinePlayChange',\n            playState: nextState,\n            from: this.uid\n        });\n    },\n\n    _handlePointerDrag: function (dx, dy, e) {\n        this._clearTimer();\n        this._pointerChangeTimeline([e.offsetX, e.offsetY]);\n    },\n\n    _handlePointerDragend: function (e) {\n        this._pointerChangeTimeline([e.offsetX, e.offsetY], true);\n    },\n\n    _pointerChangeTimeline: function (mousePos, trigger) {\n        var toCoord = this._toAxisCoord(mousePos)[0];\n\n        var axis = this._axis;\n        var axisExtent = asc(axis.getExtent().slice());\n\n        toCoord > axisExtent[1] && (toCoord = axisExtent[1]);\n        toCoord < axisExtent[0] && (toCoord = axisExtent[0]);\n\n        this._currentPointer.position[0] = toCoord;\n        this._currentPointer.dirty();\n\n        var targetDataIndex = this._findNearestTick(toCoord);\n        var timelineModel = this.model;\n\n        if (trigger || (\n            targetDataIndex !== timelineModel.getCurrentIndex()\n            && timelineModel.get('realtime')\n        )) {\n            this._changeTimeline(targetDataIndex);\n        }\n    },\n\n    _doPlayStop: function () {\n        this._clearTimer();\n\n        if (this.model.getPlayState()) {\n            this._timer = setTimeout(\n                bind$6(handleFrame, this),\n                this.model.get('playInterval')\n            );\n        }\n\n        function handleFrame() {\n            // Do not cache\n            var timelineModel = this.model;\n            this._changeTimeline(\n                timelineModel.getCurrentIndex()\n                + (timelineModel.get('rewind', true) ? -1 : 1)\n            );\n        }\n    },\n\n    _toAxisCoord: function (vertex) {\n        var trans = this._mainGroup.getLocalTransform();\n        return applyTransform$1(vertex, trans, true);\n    },\n\n    _findNearestTick: function (axisCoord) {\n        var data = this.model.getData();\n        var dist = Infinity;\n        var targetDataIndex;\n        var axis = this._axis;\n\n        data.each(['value'], function (value, dataIndex) {\n            var coord = axis.dataToCoord(value);\n            var d = Math.abs(coord - axisCoord);\n            if (d < dist) {\n                dist = d;\n                targetDataIndex = dataIndex;\n            }\n        });\n\n        return targetDataIndex;\n    },\n\n    _clearTimer: function () {\n        if (this._timer) {\n            clearTimeout(this._timer);\n            this._timer = null;\n        }\n    },\n\n    _changeTimeline: function (nextIndex) {\n        var currentIndex = this.model.getCurrentIndex();\n\n        if (nextIndex === '+') {\n            nextIndex = currentIndex + 1;\n        }\n        else if (nextIndex === '-') {\n            nextIndex = currentIndex - 1;\n        }\n\n        this.api.dispatchAction({\n            type: 'timelineChange',\n            currentIndex: nextIndex,\n            from: this.uid\n        });\n    }\n\n});\n\nfunction getViewRect$4(model, api) {\n    return getLayoutRect(\n        model.getBoxLayoutParams(),\n        {\n            width: api.getWidth(),\n            height: api.getHeight()\n        },\n        model.get('padding')\n    );\n}\n\nfunction makeIcon(timelineModel, objPath, rect, opts) {\n    var icon = makePath(\n        timelineModel.get(objPath).replace(/^path:\\/\\//, ''),\n        clone(opts || {}),\n        new BoundingRect(rect[0], rect[1], rect[2], rect[3]),\n        'center'\n    );\n\n    return icon;\n}\n\n/**\n * Create symbol or update symbol\n * opt: basic position and event handlers\n */\nfunction giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) {\n    var color = itemStyleModel.get('color');\n\n    if (!symbol) {\n        var symbolType = hostModel.get('symbol');\n        symbol = createSymbol(symbolType, -1, -1, 2, 2, color);\n        symbol.setStyle('strokeNoScale', true);\n        group.add(symbol);\n        callback && callback.onCreate(symbol);\n    }\n    else {\n        symbol.setColor(color);\n        group.add(symbol); // Group may be new, also need to add.\n        callback && callback.onUpdate(symbol);\n    }\n\n    // Style\n    var itemStyle = itemStyleModel.getItemStyle(['color', 'symbol', 'symbolSize']);\n    symbol.setStyle(itemStyle);\n\n    // Transform and events.\n    opt = merge({\n        rectHover: true,\n        z2: 100\n    }, opt, true);\n\n    var symbolSize = hostModel.get('symbolSize');\n    symbolSize = symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n    symbolSize[0] /= 2;\n    symbolSize[1] /= 2;\n    opt.scale = symbolSize;\n\n    var symbolOffset = hostModel.get('symbolOffset');\n    if (symbolOffset) {\n        var pos = opt.position = opt.position || [0, 0];\n        pos[0] += parsePercent$1(symbolOffset[0], symbolSize[0]);\n        pos[1] += parsePercent$1(symbolOffset[1], symbolSize[1]);\n    }\n\n    var symbolRotate = hostModel.get('symbolRotate');\n    opt.rotation = (symbolRotate || 0) * Math.PI / 180 || 0;\n\n    symbol.attr(opt);\n\n    // FIXME\n    // (1) When symbol.style.strokeNoScale is true and updateTransform is not performed,\n    // getBoundingRect will return wrong result.\n    // (This is supposed to be resolved in zrender, but it is a little difficult to\n    // leverage performance and auto updateTransform)\n    // (2) All of ancesters of symbol do not scale, so we can just updateTransform symbol.\n    symbol.updateTransform();\n\n    return symbol;\n}\n\nfunction pointerMoveTo(pointer, dataIndex, axis, timelineModel, noAnimation) {\n    if (pointer.dragging) {\n        return;\n    }\n\n    var pointerModel = timelineModel.getModel('checkpointStyle');\n    var toCoord = axis.dataToCoord(timelineModel.getData().get(['value'], dataIndex));\n\n    if (noAnimation || !pointerModel.get('animation', true)) {\n        pointer.attr({position: [toCoord, 0]});\n    }\n    else {\n        pointer.stopAnimation(true);\n        pointer.animateTo(\n            {position: [toCoord, 0]},\n            pointerModel.get('animationDuration', true),\n            pointerModel.get('animationEasing', true)\n        );\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$3);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ToolboxModel = extendComponentModel({\n\n    type: 'toolbox',\n\n    layoutMode: {\n        type: 'box',\n        ignoreSize: true\n    },\n\n    optionUpdated: function () {\n        ToolboxModel.superApply(this, 'optionUpdated', arguments);\n\n        each$1(this.option.feature, function (featureOpt, featureName) {\n            var Feature = get$1(featureName);\n            Feature && merge(featureOpt, Feature.defaultOption);\n        });\n    },\n\n    defaultOption: {\n\n        show: true,\n\n        z: 6,\n\n        zlevel: 0,\n\n        orient: 'horizontal',\n\n        left: 'right',\n\n        top: 'top',\n\n        // right\n        // bottom\n\n        backgroundColor: 'transparent',\n\n        borderColor: '#ccc',\n\n        borderRadius: 0,\n\n        borderWidth: 0,\n\n        padding: 5,\n\n        itemSize: 15,\n\n        itemGap: 8,\n\n        showTitle: true,\n\n        iconStyle: {\n            borderColor: '#666',\n            color: 'none'\n        },\n        emphasis: {\n            iconStyle: {\n                borderColor: '#3E98C5'\n            }\n        }\n        // textStyle: {},\n\n        // feature\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'toolbox',\n\n    render: function (toolboxModel, ecModel, api, payload) {\n        var group = this.group;\n        group.removeAll();\n\n        if (!toolboxModel.get('show')) {\n            return;\n        }\n\n        var itemSize = +toolboxModel.get('itemSize');\n        var featureOpts = toolboxModel.get('feature') || {};\n        var features = this._features || (this._features = {});\n\n        var featureNames = [];\n        each$1(featureOpts, function (opt, name) {\n            featureNames.push(name);\n        });\n\n        (new DataDiffer(this._featureNames || [], featureNames))\n            .add(processFeature)\n            .update(processFeature)\n            .remove(curry(processFeature, null))\n            .execute();\n\n        // Keep for diff.\n        this._featureNames = featureNames;\n\n        function processFeature(newIndex, oldIndex) {\n            var featureName = featureNames[newIndex];\n            var oldName = featureNames[oldIndex];\n            var featureOpt = featureOpts[featureName];\n            var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);\n            var feature;\n\n            if (featureName && !oldName) { // Create\n                if (isUserFeatureName(featureName)) {\n                    feature = {\n                        model: featureModel,\n                        onclick: featureModel.option.onclick,\n                        featureName: featureName\n                    };\n                }\n                else {\n                    var Feature = get$1(featureName);\n                    if (!Feature) {\n                        return;\n                    }\n                    feature = new Feature(featureModel, ecModel, api);\n                }\n                features[featureName] = feature;\n            }\n            else {\n                feature = features[oldName];\n                // If feature does not exsit.\n                if (!feature) {\n                    return;\n                }\n                feature.model = featureModel;\n                feature.ecModel = ecModel;\n                feature.api = api;\n            }\n\n            if (!featureName && oldName) {\n                feature.dispose && feature.dispose(ecModel, api);\n                return;\n            }\n\n            if (!featureModel.get('show') || feature.unusable) {\n                feature.remove && feature.remove(ecModel, api);\n                return;\n            }\n\n            createIconPaths(featureModel, feature, featureName);\n\n            featureModel.setIconStatus = function (iconName, status) {\n                var option = this.option;\n                var iconPaths = this.iconPaths;\n                option.iconStatus = option.iconStatus || {};\n                option.iconStatus[iconName] = status;\n                // FIXME\n                iconPaths[iconName] && iconPaths[iconName].trigger(status);\n            };\n\n            if (feature.render) {\n                feature.render(featureModel, ecModel, api, payload);\n            }\n        }\n\n        function createIconPaths(featureModel, feature, featureName) {\n            var iconStyleModel = featureModel.getModel('iconStyle');\n            var iconStyleEmphasisModel = featureModel.getModel('emphasis.iconStyle');\n\n            // If one feature has mutiple icon. they are orginaized as\n            // {\n            //     icon: {\n            //         foo: '',\n            //         bar: ''\n            //     },\n            //     title: {\n            //         foo: '',\n            //         bar: ''\n            //     }\n            // }\n            var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');\n            var titles = featureModel.get('title') || {};\n            if (typeof icons === 'string') {\n                var icon = icons;\n                var title = titles;\n                icons = {};\n                titles = {};\n                icons[featureName] = icon;\n                titles[featureName] = title;\n            }\n            var iconPaths = featureModel.iconPaths = {};\n            each$1(icons, function (iconStr, iconName) {\n                var path = createIcon(\n                    iconStr,\n                    {},\n                    {\n                        x: -itemSize / 2,\n                        y: -itemSize / 2,\n                        width: itemSize,\n                        height: itemSize\n                    }\n                );\n                path.setStyle(iconStyleModel.getItemStyle());\n                path.hoverStyle = iconStyleEmphasisModel.getItemStyle();\n\n                setHoverStyle(path);\n\n                if (toolboxModel.get('showTitle')) {\n                    path.__title = titles[iconName];\n                    path.on('mouseover', function () {\n                            // Should not reuse above hoverStyle, which might be modified.\n                            var hoverStyle = iconStyleEmphasisModel.getItemStyle();\n                            path.setStyle({\n                                text: titles[iconName],\n                                textPosition: hoverStyle.textPosition || 'bottom',\n                                textFill: hoverStyle.fill || hoverStyle.stroke || '#000',\n                                textAlign: hoverStyle.textAlign || 'center'\n                            });\n                        })\n                        .on('mouseout', function () {\n                            path.setStyle({\n                                textFill: null\n                            });\n                        });\n                }\n                path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');\n\n                group.add(path);\n                path.on('click', bind(\n                    feature.onclick, feature, ecModel, api, iconName\n                ));\n\n                iconPaths[iconName] = path;\n            });\n        }\n\n        layout$3(group, toolboxModel, api);\n        // Render background after group is layout\n        // FIXME\n        group.add(makeBackground(group.getBoundingRect(), toolboxModel));\n\n        // Adjust icon title positions to avoid them out of screen\n        group.eachChild(function (icon) {\n            var titleText = icon.__title;\n            var hoverStyle = icon.hoverStyle;\n            // May be background element\n            if (hoverStyle && titleText) {\n                var rect = getBoundingRect(\n                    titleText, makeFont(hoverStyle)\n                );\n                var offsetX = icon.position[0] + group.position[0];\n                var offsetY = icon.position[1] + group.position[1] + itemSize;\n\n                var needPutOnTop = false;\n                if (offsetY + rect.height > api.getHeight()) {\n                    hoverStyle.textPosition = 'top';\n                    needPutOnTop = true;\n                }\n                var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);\n                if (offsetX + rect.width / 2 > api.getWidth()) {\n                    hoverStyle.textPosition = ['100%', topOffset];\n                    hoverStyle.textAlign = 'right';\n                }\n                else if (offsetX - rect.width / 2 < 0) {\n                    hoverStyle.textPosition = [0, topOffset];\n                    hoverStyle.textAlign = 'left';\n                }\n            }\n        });\n    },\n\n    updateView: function (toolboxModel, ecModel, api, payload) {\n        each$1(this._features, function (feature) {\n            feature.updateView && feature.updateView(feature.model, ecModel, api, payload);\n        });\n    },\n\n    // updateLayout: function (toolboxModel, ecModel, api, payload) {\n    //     zrUtil.each(this._features, function (feature) {\n    //         feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload);\n    //     });\n    // },\n\n    remove: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.remove && feature.remove(ecModel, api);\n        });\n        this.group.removeAll();\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.dispose && feature.dispose(ecModel, api);\n        });\n    }\n});\n\nfunction isUserFeatureName(featureName) {\n    return featureName.indexOf('my') === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8Array */\n\nvar saveAsImageLang = lang.toolbox.saveAsImage;\n\nfunction SaveAsImage(model) {\n    this.model = model;\n}\n\nSaveAsImage.defaultOption = {\n    show: true,\n    icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',\n    title: saveAsImageLang.title,\n    type: 'png',\n    // Default use option.backgroundColor\n    // backgroundColor: '#fff',\n    name: '',\n    excludeComponents: ['toolbox'],\n    pixelRatio: 1,\n    lang: saveAsImageLang.lang.slice()\n};\n\nSaveAsImage.prototype.unusable = !env$1.canvasSupported;\n\nvar proto$4 = SaveAsImage.prototype;\n\nproto$4.onclick = function (ecModel, api) {\n    var model = this.model;\n    var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';\n    var $a = document.createElement('a');\n    var type = model.get('type', true) || 'png';\n    $a.download = title + '.' + type;\n    $a.target = '_blank';\n    var url = api.getConnectedDataURL({\n        type: type,\n        backgroundColor: model.get('backgroundColor', true)\n            || ecModel.get('backgroundColor') || '#fff',\n        excludeComponents: model.get('excludeComponents'),\n        pixelRatio: model.get('pixelRatio')\n    });\n    $a.href = url;\n    // Chrome and Firefox\n    if (typeof MouseEvent === 'function' && !env$1.browser.ie && !env$1.browser.edge) {\n        var evt = new MouseEvent('click', {\n            view: window,\n            bubbles: true,\n            cancelable: false\n        });\n        $a.dispatchEvent(evt);\n    }\n    // IE\n    else {\n        if (window.navigator.msSaveOrOpenBlob) {\n            var bstr = atob(url.split(',')[1]);\n            var n = bstr.length;\n            var u8arr = new Uint8Array(n);\n            while (n--) {\n                u8arr[n] = bstr.charCodeAt(n);\n            }\n            var blob = new Blob([u8arr]);\n            window.navigator.msSaveOrOpenBlob(blob, title + '.' + type);\n        }\n        else {\n            var lang$$1 = model.get('lang');\n            var html = ''\n                + '<body style=\"margin:0;\">'\n                + '<img src=\"' + url + '\" style=\"max-width:100%;\" title=\"' + ((lang$$1 && lang$$1[0]) || '') + '\" />'\n                + '</body>';\n            var tab = window.open();\n            tab.document.write(html);\n        }\n    }\n};\n\nregister$1(\n    'saveAsImage', SaveAsImage\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar magicTypeLang = lang.toolbox.magicType;\n\nfunction MagicType(model) {\n    this.model = model;\n}\n\nMagicType.defaultOption = {\n    show: true,\n    type: [],\n    // Icon group\n    icon: {\n        /* eslint-disable */\n        line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',\n        bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',\n        stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line\n        tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'\n        /* eslint-enable */\n    },\n    // `line`, `bar`, `stack`, `tiled`\n    title: clone(magicTypeLang.title),\n    option: {},\n    seriesIndex: {}\n};\n\nvar proto$5 = MagicType.prototype;\n\nproto$5.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon');\n    var icons = {};\n    each$1(model.get('type'), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nvar seriesOptGenreator = {\n    'line': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                type: 'line',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.line') || {}, true);\n        }\n    },\n    'bar': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line') {\n            return merge({\n                id: seriesId,\n                type: 'bar',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.bar') || {}, true);\n        }\n    },\n    'stack': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: '__ec_magicType_stack__'\n            }, model.get('option.stack') || {}, true);\n        }\n    },\n    'tiled': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: ''\n            }, model.get('option.tiled') || {}, true);\n        }\n    }\n};\n\nvar radioTypes = [\n    ['line', 'bar'],\n    ['stack', 'tiled']\n];\n\nproto$5.onclick = function (ecModel, api, type) {\n    var model = this.model;\n    var seriesIndex = model.get('seriesIndex.' + type);\n    // Not supported magicType\n    if (!seriesOptGenreator[type]) {\n        return;\n    }\n    var newOption = {\n        series: []\n    };\n    var generateNewSeriesTypes = function (seriesModel) {\n        var seriesType = seriesModel.subType;\n        var seriesId = seriesModel.id;\n        var newSeriesOpt = seriesOptGenreator[type](\n            seriesType, seriesId, seriesModel, model\n        );\n        if (newSeriesOpt) {\n            // PENDING If merge original option?\n            defaults(newSeriesOpt, seriesModel.option);\n            newOption.series.push(newSeriesOpt);\n        }\n        // Modify boundaryGap\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {\n            var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n            if (categoryAxis) {\n                var axisDim = categoryAxis.dim;\n                var axisType = axisDim + 'Axis';\n                var axisModel = ecModel.queryComponents({\n                    mainType: axisType,\n                    index: seriesModel.get(name + 'Index'),\n                    id: seriesModel.get(name + 'Id')\n                })[0];\n                var axisIndex = axisModel.componentIndex;\n\n                newOption[axisType] = newOption[axisType] || [];\n                for (var i = 0; i <= axisIndex; i++) {\n                    newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {};\n                }\n                newOption[axisType][axisIndex].boundaryGap = type === 'bar';\n            }\n        }\n    };\n\n    each$1(radioTypes, function (radio) {\n        if (indexOf(radio, type) >= 0) {\n            each$1(radio, function (item) {\n                model.setIconStatus(item, 'normal');\n            });\n        }\n    });\n\n    model.setIconStatus(type, 'emphasis');\n\n    ecModel.eachComponent(\n        {\n            mainType: 'series',\n            query: seriesIndex == null ? null : {\n                seriesIndex: seriesIndex\n            }\n        }, generateNewSeriesTypes\n    );\n    api.dispatchAction({\n        type: 'changeMagicType',\n        currentType: type,\n        newOption: newOption\n    });\n};\n\nregisterAction({\n    type: 'changeMagicType',\n    event: 'magicTypeChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    ecModel.mergeOption(payload.newOption);\n});\n\nregister$1('magicType', MagicType);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataViewLang = lang.toolbox.dataView;\n\nvar BLOCK_SPLITER = new Array(60).join('-');\nvar ITEM_SPLITER = '\\t';\n/**\n * Group series into two types\n *  1. on category axis, like line, bar\n *  2. others, like scatter, pie\n * @param {module:echarts/model/Global} ecModel\n * @return {Object}\n * @inner\n */\nfunction groupSeries(ecModel) {\n    var seriesGroupByCategoryAxis = {};\n    var otherSeries = [];\n    var meta = [];\n    ecModel.eachRawSeries(function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {\n            var baseAxis = coordSys.getBaseAxis();\n            if (baseAxis.type === 'category') {\n                var key = baseAxis.dim + '_' + baseAxis.index;\n                if (!seriesGroupByCategoryAxis[key]) {\n                    seriesGroupByCategoryAxis[key] = {\n                        categoryAxis: baseAxis,\n                        valueAxis: coordSys.getOtherAxis(baseAxis),\n                        series: []\n                    };\n                    meta.push({\n                        axisDim: baseAxis.dim,\n                        axisIndex: baseAxis.index\n                    });\n                }\n                seriesGroupByCategoryAxis[key].series.push(seriesModel);\n            }\n            else {\n                otherSeries.push(seriesModel);\n            }\n        }\n        else {\n            otherSeries.push(seriesModel);\n        }\n    });\n\n    return {\n        seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,\n        other: otherSeries,\n        meta: meta\n    };\n}\n\n/**\n * Assemble content of series on cateogory axis\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleSeriesWithCategoryAxis(series) {\n    var tables = [];\n    each$1(series, function (group, key) {\n        var categoryAxis = group.categoryAxis;\n        var valueAxis = group.valueAxis;\n        var valueAxisDim = valueAxis.dim;\n\n        var headers = [' '].concat(map(group.series, function (series) {\n            return series.name;\n        }));\n        var columns = [categoryAxis.model.getCategories()];\n        each$1(group.series, function (series) {\n            columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {\n                return val;\n            }));\n        });\n        // Assemble table content\n        var lines = [headers.join(ITEM_SPLITER)];\n        for (var i = 0; i < columns[0].length; i++) {\n            var items = [];\n            for (var j = 0; j < columns.length; j++) {\n                items.push(columns[j][i]);\n            }\n            lines.push(items.join(ITEM_SPLITER));\n        }\n        tables.push(lines.join('\\n'));\n    });\n    return tables.join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * Assemble content of other series\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleOtherSeries(series) {\n    return map(series, function (series) {\n        var data = series.getRawData();\n        var lines = [series.name];\n        var vals = [];\n        data.each(data.dimensions, function () {\n            var argLen = arguments.length;\n            var dataIndex = arguments[argLen - 1];\n            var name = data.getName(dataIndex);\n            for (var i = 0; i < argLen - 1; i++) {\n                vals[i] = arguments[i];\n            }\n            lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));\n        });\n        return lines.join('\\n');\n    }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * @param {module:echarts/model/Global}\n * @return {Object}\n * @inner\n */\nfunction getContentFromModel(ecModel) {\n\n    var result = groupSeries(ecModel);\n\n    return {\n        value: filter([\n                assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),\n                assembleOtherSeries(result.other)\n            ], function (str) {\n                return str.replace(/[\\n\\t\\s]/g, '');\n            }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n'),\n\n        meta: result.meta\n    };\n}\n\n\nfunction trim$1(str) {\n    return str.replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n}\n/**\n * If a block is tsv format\n */\nfunction isTSVFormat(block) {\n    // Simple method to find out if a block is tsv format\n    var firstLine = block.slice(0, block.indexOf('\\n'));\n    if (firstLine.indexOf(ITEM_SPLITER) >= 0) {\n        return true;\n    }\n}\n\nvar itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');\n/**\n * @param {string} tsv\n * @return {Object}\n */\nfunction parseTSVContents(tsv) {\n    var tsvLines = tsv.split(/\\n+/g);\n    var headers = trim$1(tsvLines.shift()).split(itemSplitRegex);\n\n    var categories = [];\n    var series = map(headers, function (header) {\n        return {\n            name: header,\n            data: []\n        };\n    });\n    for (var i = 0; i < tsvLines.length; i++) {\n        var items = trim$1(tsvLines[i]).split(itemSplitRegex);\n        categories.push(items.shift());\n        for (var j = 0; j < items.length; j++) {\n            series[j] && (series[j].data[i] = items[j]);\n        }\n    }\n    return {\n        series: series,\n        categories: categories\n    };\n}\n\n/**\n * @param {string} str\n * @return {Array.<Object>}\n * @inner\n */\nfunction parseListContents(str) {\n    var lines = str.split(/\\n+/g);\n    var seriesName = trim$1(lines.shift());\n\n    var data = [];\n    for (var i = 0; i < lines.length; i++) {\n        var items = trim$1(lines[i]).split(itemSplitRegex);\n        var name = '';\n        var value;\n        var hasName = false;\n        if (isNaN(items[0])) { // First item is name\n            hasName = true;\n            name = items[0];\n            items = items.slice(1);\n            data[i] = {\n                name: name,\n                value: []\n            };\n            value = data[i].value;\n        }\n        else {\n            value = data[i] = [];\n        }\n        for (var j = 0; j < items.length; j++) {\n            value.push(+items[j]);\n        }\n        if (value.length === 1) {\n            hasName ? (data[i].value = value[0]) : (data[i] = value[0]);\n        }\n    }\n\n    return {\n        name: seriesName,\n        data: data\n    };\n}\n\n/**\n * @param {string} str\n * @param {Array.<Object>} blockMetaList\n * @return {Object}\n * @inner\n */\nfunction parseContents(str, blockMetaList) {\n    var blocks = str.split(new RegExp('\\n*' + BLOCK_SPLITER + '\\n*', 'g'));\n    var newOption = {\n        series: []\n    };\n    each$1(blocks, function (block, idx) {\n        if (isTSVFormat(block)) {\n            var result = parseTSVContents(block);\n            var blockMeta = blockMetaList[idx];\n            var axisKey = blockMeta.axisDim + 'Axis';\n\n            if (blockMeta) {\n                newOption[axisKey] = newOption[axisKey] || [];\n                newOption[axisKey][blockMeta.axisIndex] = {\n                    data: result.categories\n                };\n                newOption.series = newOption.series.concat(result.series);\n            }\n        }\n        else {\n            var result = parseListContents(block);\n            newOption.series.push(result);\n        }\n    });\n    return newOption;\n}\n\n/**\n * @alias {module:echarts/component/toolbox/feature/DataView}\n * @constructor\n * @param {module:echarts/model/Model} model\n */\nfunction DataView(model) {\n\n    this._dom = null;\n\n    this.model = model;\n}\n\nDataView.defaultOption = {\n    show: true,\n    readOnly: false,\n    optionToContent: null,\n    contentToOption: null,\n\n    icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',\n    title: clone(dataViewLang.title),\n    lang: clone(dataViewLang.lang),\n    backgroundColor: '#fff',\n    textColor: '#000',\n    textareaColor: '#fff',\n    textareaBorderColor: '#333',\n    buttonColor: '#c23531',\n    buttonTextColor: '#fff'\n};\n\nDataView.prototype.onclick = function (ecModel, api) {\n    var container = api.getDom();\n    var model = this.model;\n    if (this._dom) {\n        container.removeChild(this._dom);\n    }\n    var root = document.createElement('div');\n    root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';\n    root.style.backgroundColor = model.get('backgroundColor') || '#fff';\n\n    // Create elements\n    var header = document.createElement('h4');\n    var lang$$1 = model.get('lang') || [];\n    header.innerHTML = lang$$1[0] || model.get('title');\n    header.style.cssText = 'margin: 10px 20px;';\n    header.style.color = model.get('textColor');\n\n    var viewMain = document.createElement('div');\n    var textarea = document.createElement('textarea');\n    viewMain.style.cssText = 'display:block;width:100%;overflow:auto;';\n\n    var optionToContent = model.get('optionToContent');\n    var contentToOption = model.get('contentToOption');\n    var result = getContentFromModel(ecModel);\n    if (typeof optionToContent === 'function') {\n        var htmlOrDom = optionToContent(api.getOption());\n        if (typeof htmlOrDom === 'string') {\n            viewMain.innerHTML = htmlOrDom;\n        }\n        else if (isDom(htmlOrDom)) {\n            viewMain.appendChild(htmlOrDom);\n        }\n    }\n    else {\n        // Use default textarea\n        viewMain.appendChild(textarea);\n        textarea.readOnly = model.get('readOnly');\n        textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';\n        textarea.style.color = model.get('textColor');\n        textarea.style.borderColor = model.get('textareaBorderColor');\n        textarea.style.backgroundColor = model.get('textareaColor');\n        textarea.value = result.value;\n    }\n\n    var blockMetaList = result.meta;\n\n    var buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';\n\n    var buttonStyle = 'float:right;margin-right:20px;border:none;'\n        + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';\n    var closeButton = document.createElement('div');\n    var refreshButton = document.createElement('div');\n\n    buttonStyle += ';background-color:' + model.get('buttonColor');\n    buttonStyle += ';color:' + model.get('buttonTextColor');\n\n    var self = this;\n\n    function close() {\n        container.removeChild(root);\n        self._dom = null;\n    }\n    addEventListener(closeButton, 'click', close);\n\n    addEventListener(refreshButton, 'click', function () {\n        var newOption;\n        try {\n            if (typeof contentToOption === 'function') {\n                newOption = contentToOption(viewMain, api.getOption());\n            }\n            else {\n                newOption = parseContents(textarea.value, blockMetaList);\n            }\n        }\n        catch (e) {\n            close();\n            throw new Error('Data view format error ' + e);\n        }\n        if (newOption) {\n            api.dispatchAction({\n                type: 'changeDataView',\n                newOption: newOption\n            });\n        }\n\n        close();\n    });\n\n    closeButton.innerHTML = lang$$1[1];\n    refreshButton.innerHTML = lang$$1[2];\n    refreshButton.style.cssText = buttonStyle;\n    closeButton.style.cssText = buttonStyle;\n\n    !model.get('readOnly') && buttonContainer.appendChild(refreshButton);\n    buttonContainer.appendChild(closeButton);\n\n    // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea\n    addEventListener(textarea, 'keydown', function (e) {\n        if ((e.keyCode || e.which) === 9) {\n            // get caret position/selection\n            var val = this.value;\n            var start = this.selectionStart;\n            var end = this.selectionEnd;\n\n            // set textarea value to: text before caret + tab + text after caret\n            this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);\n\n            // put caret at right position again\n            this.selectionStart = this.selectionEnd = start + 1;\n\n            // prevent the focus lose\n            stop(e);\n        }\n    });\n\n    root.appendChild(header);\n    root.appendChild(viewMain);\n    root.appendChild(buttonContainer);\n\n    viewMain.style.height = (container.clientHeight - 80) + 'px';\n\n    container.appendChild(root);\n    this._dom = root;\n};\n\nDataView.prototype.remove = function (ecModel, api) {\n    this._dom && api.getDom().removeChild(this._dom);\n};\n\nDataView.prototype.dispose = function (ecModel, api) {\n    this.remove(ecModel, api);\n};\n\n/**\n * @inner\n */\nfunction tryMergeDataOption(newData, originalData) {\n    return map(newData, function (newVal, idx) {\n        var original = originalData && originalData[idx];\n        if (isObject$1(original) && !isArray(original)) {\n            if (isObject$1(newVal) && !isArray(newVal)) {\n                newVal = newVal.value;\n            }\n            // Original data has option\n            return defaults({\n                value: newVal\n            }, original);\n        }\n        else {\n            return newVal;\n        }\n    });\n}\n\nregister$1('dataView', DataView);\n\nregisterAction({\n    type: 'changeDataView',\n    event: 'dataViewChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    var newSeriesOptList = [];\n    each$1(payload.newOption.series, function (seriesOpt) {\n        var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];\n        if (!seriesModel) {\n            // New created series\n            // Geuss the series type\n            newSeriesOptList.push(extend({\n                // Default is scatter\n                type: 'scatter'\n            }, seriesOpt));\n        }\n        else {\n            var originalData = seriesModel.get('data');\n            newSeriesOptList.push({\n                name: seriesOpt.name,\n                data: tryMergeDataOption(seriesOpt.data, originalData)\n            });\n        }\n    });\n\n    ecModel.mergeOption(defaults({\n        series: newSeriesOptList\n    }, payload.newOption));\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$29 = each$1;\n\nvar ATTR$2 = '\\0_ec_hist_store';\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}\n */\nfunction push(ecModel, newSnapshot) {\n    var store = giveStore$1(ecModel);\n\n    // If previous dataZoom can not be found,\n    // complete an range with current range.\n    each$29(newSnapshot, function (batchItem, dataZoomId) {\n        var i = store.length - 1;\n        for (; i >= 0; i--) {\n            var snapshot = store[i];\n            if (snapshot[dataZoomId]) {\n                break;\n            }\n        }\n        if (i < 0) {\n            // No origin range set, create one by current range.\n            var dataZoomModel = ecModel.queryComponents(\n                {mainType: 'dataZoom', subType: 'select', id: dataZoomId}\n            )[0];\n            if (dataZoomModel) {\n                var percentRange = dataZoomModel.getPercentRange();\n                store[0][dataZoomId] = {\n                    dataZoomId: dataZoomId,\n                    start: percentRange[0],\n                    end: percentRange[1]\n                };\n            }\n        }\n    });\n\n    store.push(newSnapshot);\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} snapshot\n */\nfunction pop(ecModel) {\n    var store = giveStore$1(ecModel);\n    var head = store[store.length - 1];\n    store.length > 1 && store.pop();\n\n    // Find top for all dataZoom.\n    var snapshot = {};\n    each$29(head, function (batchItem, dataZoomId) {\n        for (var i = store.length - 1; i >= 0; i--) {\n            var batchItem = store[i][dataZoomId];\n            if (batchItem) {\n                snapshot[dataZoomId] = batchItem;\n                break;\n            }\n        }\n    });\n\n    return snapshot;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n */\nfunction clear$1(ecModel) {\n    ecModel[ATTR$2] = null;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {number} records. always >= 1.\n */\nfunction count(ecModel) {\n    return giveStore$1(ecModel).length;\n}\n\n/**\n * [{key: dataZoomId, value: {dataZoomId, range}}, ...]\n * History length of each dataZoom may be different.\n * this._history[0] is used to store origin range.\n * @type {Array.<Object>}\n */\nfunction giveStore$1(ecModel) {\n    var store = ecModel[ATTR$2];\n    if (!store) {\n        store = ecModel[ATTR$2] = [{}];\n    }\n    return store;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomView.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Use dataZoomSelect\nvar dataZoomLang = lang.toolbox.dataZoom;\nvar each$28 = each$1;\n\n// Spectial component id start with \\0ec\\0, see echarts/model/Global.js~hasInnerId\nvar DATA_ZOOM_ID_BASE = '\\0_ec_\\0toolbox-dataZoom_';\n\nfunction DataZoom(model, ecModel, api) {\n\n    /**\n     * @private\n     * @type {module:echarts/component/helper/BrushController}\n     */\n    (this._brushController = new BrushController(api.getZr()))\n        .on('brush', bind(this._onBrush, this))\n        .mount();\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._isZoomActive;\n}\n\nDataZoom.defaultOption = {\n    show: true,\n    // Icon group\n    icon: {\n        zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',\n        back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'\n    },\n    // `zoom`, `back`\n    title: clone(dataZoomLang.title)\n};\n\nvar proto$6 = DataZoom.prototype;\n\nproto$6.render = function (featureModel, ecModel, api, payload) {\n    this.model = featureModel;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    updateZoomBtnStatus(featureModel, ecModel, this, payload, api);\n    updateBackBtnStatus(featureModel, ecModel);\n};\n\nproto$6.onclick = function (ecModel, api, type) {\n    handlers$1[type].call(this);\n};\n\nproto$6.remove = function (ecModel, api) {\n    this._brushController.unmount();\n};\n\nproto$6.dispose = function (ecModel, api) {\n    this._brushController.dispose();\n};\n\n/**\n * @private\n */\nvar handlers$1 = {\n\n    zoom: function () {\n        var nextActive = !this._isZoomActive;\n\n        this.api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'dataZoomSelect',\n            dataZoomSelectActive: nextActive\n        });\n    },\n\n    back: function () {\n        this._dispatchZoomAction(pop(this.ecModel));\n    }\n};\n\n/**\n * @private\n */\nproto$6._onBrush = function (areas, opt) {\n    if (!opt.isEnd || !areas.length) {\n        return;\n    }\n    var snapshot = {};\n    var ecModel = this.ecModel;\n\n    this._brushController.updateCovers([]); // remove cover\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(this.model.option), ecModel, {include: ['grid']}\n    );\n    brushTargetManager.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        if (coordSys.type !== 'cartesian2d') {\n            return;\n        }\n\n        var brushType = area.brushType;\n        if (brushType === 'rect') {\n            setBatch('x', coordSys, coordRange[0]);\n            setBatch('y', coordSys, coordRange[1]);\n        }\n        else {\n            setBatch(({lineX: 'x', lineY: 'y'})[brushType], coordSys, coordRange);\n        }\n    });\n\n    push(ecModel, snapshot);\n\n    this._dispatchZoomAction(snapshot);\n\n    function setBatch(dimName, coordSys, minMax) {\n        var axis = coordSys.getAxis(dimName);\n        var axisModel = axis.model;\n        var dataZoomModel = findDataZoom(dimName, axisModel, ecModel);\n\n        // Restrict range.\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy(axisModel).getMinMaxSpan();\n        if (minMaxSpan.minValueSpan != null || minMaxSpan.maxValueSpan != null) {\n            minMax = sliderMove(\n                0, minMax.slice(), axis.scale.getExtent(), 0,\n                minMaxSpan.minValueSpan, minMaxSpan.maxValueSpan\n            );\n        }\n\n        dataZoomModel && (snapshot[dataZoomModel.id] = {\n            dataZoomId: dataZoomModel.id,\n            startValue: minMax[0],\n            endValue: minMax[1]\n        });\n    }\n\n    function findDataZoom(dimName, axisModel, ecModel) {\n        var found;\n        ecModel.eachComponent({mainType: 'dataZoom', subType: 'select'}, function (dzModel) {\n            var has = dzModel.getAxisModel(dimName, axisModel.componentIndex);\n            has && (found = dzModel);\n        });\n        return found;\n    }\n};\n\n/**\n * @private\n */\nproto$6._dispatchZoomAction = function (snapshot) {\n    var batch = [];\n\n    // Convert from hash map to array.\n    each$28(snapshot, function (batchItem, dataZoomId) {\n        batch.push(clone(batchItem));\n    });\n\n    batch.length && this.api.dispatchAction({\n        type: 'dataZoom',\n        from: this.uid,\n        batch: batch\n    });\n};\n\nfunction retrieveAxisSetting(option) {\n    var setting = {};\n    // Compatible with previous setting: null => all axis, false => no axis.\n    each$1(['xAxisIndex', 'yAxisIndex'], function (name) {\n        setting[name] = option[name];\n        setting[name] == null && (setting[name] = 'all');\n        (setting[name] === false || setting[name] === 'none') && (setting[name] = []);\n    });\n    return setting;\n}\n\nfunction updateBackBtnStatus(featureModel, ecModel) {\n    featureModel.setIconStatus(\n        'back',\n        count(ecModel) > 1 ? 'emphasis' : 'normal'\n    );\n}\n\nfunction updateZoomBtnStatus(featureModel, ecModel, view, payload, api) {\n    var zoomActive = view._isZoomActive;\n\n    if (payload && payload.type === 'takeGlobalCursor') {\n        zoomActive = payload.key === 'dataZoomSelect'\n            ? payload.dataZoomSelectActive : false;\n    }\n\n    view._isZoomActive = zoomActive;\n\n    featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal');\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(featureModel.option), ecModel, {include: ['grid']}\n    );\n\n    view._brushController\n        .setPanels(brushTargetManager.makePanelOpts(api, function (targetInfo) {\n            return (targetInfo.xAxisDeclared && !targetInfo.yAxisDeclared)\n                ? 'lineX'\n                : (!targetInfo.xAxisDeclared && targetInfo.yAxisDeclared)\n                ? 'lineY'\n                : 'rect';\n        }))\n        .enableBrush(\n            zoomActive\n            ? {\n                brushType: 'auto',\n                brushStyle: {\n                    // FIXME user customized?\n                    lineWidth: 0,\n                    fill: 'rgba(0,0,0,0.2)'\n                }\n            }\n            : false\n        );\n}\n\n\nregister$1('dataZoom', DataZoom);\n\n\n// Create special dataZoom option for select\n// FIXME consider the case of merge option, where axes options are not exists.\nregisterPreprocessor(function (option) {\n    if (!option) {\n        return;\n    }\n\n    var dataZoomOpts = option.dataZoom || (option.dataZoom = []);\n    if (!isArray(dataZoomOpts)) {\n        option.dataZoom = dataZoomOpts = [dataZoomOpts];\n    }\n\n    var toolboxOpt = option.toolbox;\n    if (toolboxOpt) {\n        // Assume there is only one toolbox\n        if (isArray(toolboxOpt)) {\n            toolboxOpt = toolboxOpt[0];\n        }\n\n        if (toolboxOpt && toolboxOpt.feature) {\n            var dataZoomOpt = toolboxOpt.feature.dataZoom;\n            // FIXME: If add dataZoom when setOption in merge mode,\n            // no axis info to be added. See `test/dataZoom-extreme.html`\n            addForAxis('xAxis', dataZoomOpt);\n            addForAxis('yAxis', dataZoomOpt);\n        }\n    }\n\n    function addForAxis(axisName, dataZoomOpt) {\n        if (!dataZoomOpt) {\n            return;\n        }\n\n        // Try not to modify model, because it is not merged yet.\n        var axisIndicesName = axisName + 'Index';\n        var givenAxisIndices = dataZoomOpt[axisIndicesName];\n        if (givenAxisIndices != null\n            && givenAxisIndices !== 'all'\n            && !isArray(givenAxisIndices)\n        ) {\n            givenAxisIndices = (givenAxisIndices === false || givenAxisIndices === 'none') ? [] : [givenAxisIndices];\n        }\n\n        forEachComponent(axisName, function (axisOpt, axisIndex) {\n            if (givenAxisIndices != null\n                && givenAxisIndices !== 'all'\n                && indexOf(givenAxisIndices, axisIndex) === -1\n            ) {\n                return;\n            }\n            var newOpt = {\n                type: 'select',\n                $fromToolbox: true,\n                // Id for merge mapping.\n                id: DATA_ZOOM_ID_BASE + axisName + axisIndex\n            };\n            // FIXME\n            // Only support one axis now.\n            newOpt[axisIndicesName] = axisIndex;\n            dataZoomOpts.push(newOpt);\n        });\n    }\n\n    function forEachComponent(mainType, cb) {\n        var opts = option[mainType];\n        if (!isArray(opts)) {\n            opts = opts ? [opts] : [];\n        }\n        each$28(opts, cb);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar restoreLang = lang.toolbox.restore;\n\nfunction Restore(model) {\n    this.model = model;\n}\n\nRestore.defaultOption = {\n    show: true,\n    /* eslint-disable */\n    icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',\n    /* eslint-enable */\n    title: restoreLang.title\n};\n\nvar proto$7 = Restore.prototype;\n\nproto$7.onclick = function (ecModel, api, type) {\n    clear$1(ecModel);\n\n    api.dispatchAction({\n        type: 'restore',\n        from: this.uid\n    });\n};\n\nregister$1('restore', Restore);\n\nregisterAction(\n    {type: 'restore', event: 'restore', update: 'prepareAndUpdate'},\n    function (payload, ecModel) {\n        ecModel.resetOption('recreate');\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar urn = 'urn:schemas-microsoft-com:vml';\nvar win = typeof window === 'undefined' ? null : window;\n\nvar vmlInited = false;\n\nvar doc = win && win.document;\n\nfunction createNode(tagName) {\n    return doCreateNode(tagName);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar doCreateNode;\n\nif (doc && !env$1.canvasSupported) {\n    try {\n        !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);\n        doCreateNode = function (tagName) {\n            return doc.createElement('<zrvml:' + tagName + ' class=\"zrvml\">');\n        };\n    }\n    catch (e) {\n        doCreateNode = function (tagName) {\n            return doc.createElement('<' + tagName + ' xmlns=\"' + urn + '\" class=\"zrvml\">');\n        };\n    }\n}\n\n// From raphael\nfunction initVML() {\n    if (vmlInited || !doc) {\n        return;\n    }\n    vmlInited = true;\n\n    var styleSheets = doc.styleSheets;\n    if (styleSheets.length < 31) {\n        doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n    else {\n        // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx\n        styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n}\n\n// http://www.w3.org/TR/NOTE-VML\n// TODO Use proxy like svg instead of overwrite brush methods\n\nvar CMD$3 = PathProxy.CMD;\nvar round$4 = Math.round;\nvar sqrt = Math.sqrt;\nvar abs$1 = Math.abs;\nvar cos = Math.cos;\nvar sin = Math.sin;\nvar mathMax$8 = Math.max;\n\nif (!env$1.canvasSupported) {\n\n    var comma = ',';\n    var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';\n\n    var Z = 21600;\n    var Z2 = Z / 2;\n\n    var ZLEVEL_BASE = 100000;\n    var Z_BASE$1 = 1000;\n\n    var initRootElStyle = function (el) {\n        el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';\n        el.coordsize = Z + ',' + Z;\n        el.coordorigin = '0,0';\n    };\n\n    var encodeHtmlAttribute = function (s) {\n        return String(s).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\n    };\n\n    var rgb2Str = function (r, g, b) {\n        return 'rgb(' + [r, g, b].join(',') + ')';\n    };\n\n    var append = function (parent, child) {\n        if (child && parent && child.parentNode !== parent) {\n            parent.appendChild(child);\n        }\n    };\n\n    var remove = function (parent, child) {\n        if (child && parent && child.parentNode === parent) {\n            parent.removeChild(child);\n        }\n    };\n\n    var getZIndex = function (zlevel, z, z2) {\n        // z 的取值范围为 [0, 1000]\n        return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE$1 + z2;\n    };\n\n    var parsePercent$3 = function (value, maxValue) {\n        if (typeof value === 'string') {\n            if (value.lastIndexOf('%') >= 0) {\n                return parseFloat(value) / 100 * maxValue;\n            }\n            return parseFloat(value);\n        }\n        return value;\n    };\n\n    /***************************************************\n     * PATH\n     **************************************************/\n\n    var setColorAndOpacity = function (el, color, opacity) {\n        var colorArr = parse(color);\n        opacity = +opacity;\n        if (isNaN(opacity)) {\n            opacity = 1;\n        }\n        if (colorArr) {\n            el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);\n            el.opacity = opacity * colorArr[3];\n        }\n    };\n\n    var getColorAndAlpha = function (color) {\n        var colorArr = parse(color);\n        return [\n            rgb2Str(colorArr[0], colorArr[1], colorArr[2]),\n            colorArr[3]\n        ];\n    };\n\n    var updateFillNode = function (el, style, zrEl) {\n        // TODO pattern\n        var fill = style.fill;\n        if (fill != null) {\n            // Modified from excanvas\n            if (fill instanceof Gradient) {\n                var gradientType;\n                var angle = 0;\n                var focus = [0, 0];\n                // additional offset\n                var shift = 0;\n                // scale factor for offset\n                var expansion = 1;\n                var rect = zrEl.getBoundingRect();\n                var rectWidth = rect.width;\n                var rectHeight = rect.height;\n                if (fill.type === 'linear') {\n                    gradientType = 'gradient';\n                    var transform = zrEl.transform;\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                        applyTransform(p1, p1, transform);\n                    }\n                    var dx = p1[0] - p0[0];\n                    var dy = p1[1] - p0[1];\n                    angle = Math.atan2(dx, dy) * 180 / Math.PI;\n                    // The angle should be a non-negative number.\n                    if (angle < 0) {\n                        angle += 360;\n                    }\n\n                    // Very small angles produce an unexpected result because they are\n                    // converted to a scientific notation string.\n                    if (angle < 1e-6) {\n                        angle = 0;\n                    }\n                }\n                else {\n                    gradientType = 'gradientradial';\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var transform = zrEl.transform;\n                    var scale$$1 = zrEl.scale;\n                    var width = rectWidth;\n                    var height = rectHeight;\n                    focus = [\n                        // Percent in bounding rect\n                        (p0[0] - rect.x) / width,\n                        (p0[1] - rect.y) / height\n                    ];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                    }\n\n                    width /= scale$$1[0] * Z;\n                    height /= scale$$1[1] * Z;\n                    var dimension = mathMax$8(width, height);\n                    shift = 2 * 0 / dimension;\n                    expansion = 2 * fill.r / dimension - shift;\n                }\n\n                // We need to sort the color stops in ascending order by offset,\n                // otherwise IE won't interpret it correctly.\n                var stops = fill.colorStops.slice();\n                stops.sort(function (cs1, cs2) {\n                    return cs1.offset - cs2.offset;\n                });\n\n                var length$$1 = stops.length;\n                // Color and alpha list of first and last stop\n                var colorAndAlphaList = [];\n                var colors = [];\n                for (var i = 0; i < length$$1; i++) {\n                    var stop = stops[i];\n                    var colorAndAlpha = getColorAndAlpha(stop.color);\n                    colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);\n                    if (i === 0 || i === length$$1 - 1) {\n                        colorAndAlphaList.push(colorAndAlpha);\n                    }\n                }\n\n                if (length$$1 >= 2) {\n                    var color1 = colorAndAlphaList[0][0];\n                    var color2 = colorAndAlphaList[1][0];\n                    var opacity1 = colorAndAlphaList[0][1] * style.opacity;\n                    var opacity2 = colorAndAlphaList[1][1] * style.opacity;\n\n                    el.type = gradientType;\n                    el.method = 'none';\n                    el.focus = '100%';\n                    el.angle = angle;\n                    el.color = color1;\n                    el.color2 = color2;\n                    el.colors = colors.join(',');\n                    // When colors attribute is used, the meanings of opacity and o:opacity2\n                    // are reversed.\n                    el.opacity = opacity2;\n                    // FIXME g_o_:opacity ?\n                    el.opacity2 = opacity1;\n                }\n                if (gradientType === 'radial') {\n                    el.focusposition = focus.join(',');\n                }\n            }\n            else {\n                // FIXME Change from Gradient fill to color fill\n                setColorAndOpacity(el, fill, style.opacity);\n            }\n        }\n    };\n\n    var updateStrokeNode = function (el, style) {\n        // if (style.lineJoin != null) {\n        //     el.joinstyle = style.lineJoin;\n        // }\n        // if (style.miterLimit != null) {\n        //     el.miterlimit = style.miterLimit * Z;\n        // }\n        // if (style.lineCap != null) {\n        //     el.endcap = style.lineCap;\n        // }\n        if (style.lineDash != null) {\n            el.dashstyle = style.lineDash.join(' ');\n        }\n        if (style.stroke != null && !(style.stroke instanceof Gradient)) {\n            setColorAndOpacity(el, style.stroke, style.opacity);\n        }\n    };\n\n    var updateFillAndStroke = function (vmlEl, type, style, zrEl) {\n        var isFill = type === 'fill';\n        var el = vmlEl.getElementsByTagName(type)[0];\n        // Stroke must have lineWidth\n        if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'true';\n            // FIXME Remove before updating, or set `colors` will throw error\n            if (style[type] instanceof Gradient) {\n                remove(vmlEl, el);\n            }\n            if (!el) {\n                el = createNode(type);\n            }\n\n            isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);\n            append(vmlEl, el);\n        }\n        else {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'false';\n            remove(vmlEl, el);\n        }\n    };\n\n    var points$3 = [[], [], []];\n    var pathDataToString = function (path, m) {\n        var M = CMD$3.M;\n        var C = CMD$3.C;\n        var L = CMD$3.L;\n        var A = CMD$3.A;\n        var Q = CMD$3.Q;\n\n        var str = [];\n        var nPoint;\n        var cmdStr;\n        var cmd;\n        var i;\n        var xi;\n        var yi;\n        var data = path.data;\n        var dataLength = path.len();\n        for (i = 0; i < dataLength;) {\n            cmd = data[i++];\n            cmdStr = '';\n            nPoint = 0;\n            switch (cmd) {\n                case M:\n                    cmdStr = ' m ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$3[0][0] = xi;\n                    points$3[0][1] = yi;\n                    break;\n                case L:\n                    cmdStr = ' l ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$3[0][0] = xi;\n                    points$3[0][1] = yi;\n                    break;\n                case Q:\n                case C:\n                    cmdStr = ' c ';\n                    nPoint = 3;\n                    var x1 = data[i++];\n                    var y1 = data[i++];\n                    var x2 = data[i++];\n                    var y2 = data[i++];\n                    var x3;\n                    var y3;\n                    if (cmd === Q) {\n                        // Convert quadratic to cubic using degree elevation\n                        x3 = x2;\n                        y3 = y2;\n                        x2 = (x2 + 2 * x1) / 3;\n                        y2 = (y2 + 2 * y1) / 3;\n                        x1 = (xi + 2 * x1) / 3;\n                        y1 = (yi + 2 * y1) / 3;\n                    }\n                    else {\n                        x3 = data[i++];\n                        y3 = data[i++];\n                    }\n                    points$3[0][0] = x1;\n                    points$3[0][1] = y1;\n                    points$3[1][0] = x2;\n                    points$3[1][1] = y2;\n                    points$3[2][0] = x3;\n                    points$3[2][1] = y3;\n\n                    xi = x3;\n                    yi = y3;\n                    break;\n                case A:\n                    var x = 0;\n                    var y = 0;\n                    var sx = 1;\n                    var sy = 1;\n                    var angle = 0;\n                    if (m) {\n                        // Extract SRT from matrix\n                        x = m[4];\n                        y = m[5];\n                        sx = sqrt(m[0] * m[0] + m[1] * m[1]);\n                        sy = sqrt(m[2] * m[2] + m[3] * m[3]);\n                        angle = Math.atan2(-m[1] / sy, m[0] / sx);\n                    }\n\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++] + angle;\n                    var endAngle = data[i++] + startAngle + angle;\n                    // FIXME\n                    // var psi = data[i++];\n                    i++;\n                    var clockwise = data[i++];\n\n                    var x0 = cx + cos(startAngle) * rx;\n                    var y0 = cy + sin(startAngle) * ry;\n\n                    var x1 = cx + cos(endAngle) * rx;\n                    var y1 = cy + sin(endAngle) * ry;\n\n                    var type = clockwise ? ' wa ' : ' at ';\n                    if (Math.abs(x0 - x1) < 1e-4) {\n                        // IE won't render arches drawn counter clockwise if x0 == x1.\n                        if (Math.abs(endAngle - startAngle) > 1e-2) {\n                            // Offset x0 by 1/80 of a pixel. Use something\n                            // that can be represented in binary\n                            if (clockwise) {\n                                x0 += 270 / Z;\n                            }\n                        }\n                        else {\n                            // Avoid case draw full circle\n                            if (Math.abs(y0 - cy) < 1e-4) {\n                                if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) {\n                                    y1 -= 270 / Z;\n                                }\n                                else {\n                                    y1 += 270 / Z;\n                                }\n                            }\n                            else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) {\n                                x1 += 270 / Z;\n                            }\n                            else {\n                                x1 -= 270 / Z;\n                            }\n                        }\n                    }\n                    str.push(\n                        type,\n                        round$4(((cx - rx) * sx + x) * Z - Z2), comma,\n                        round$4(((cy - ry) * sy + y) * Z - Z2), comma,\n                        round$4(((cx + rx) * sx + x) * Z - Z2), comma,\n                        round$4(((cy + ry) * sy + y) * Z - Z2), comma,\n                        round$4((x0 * sx + x) * Z - Z2), comma,\n                        round$4((y0 * sy + y) * Z - Z2), comma,\n                        round$4((x1 * sx + x) * Z - Z2), comma,\n                        round$4((y1 * sy + y) * Z - Z2)\n                    );\n\n                    xi = x1;\n                    yi = y1;\n                    break;\n                case CMD$3.R:\n                    var p0 = points$3[0];\n                    var p1 = points$3[1];\n                    // x0, y0\n                    p0[0] = data[i++];\n                    p0[1] = data[i++];\n                    // x1, y1\n                    p1[0] = p0[0] + data[i++];\n                    p1[1] = p0[1] + data[i++];\n\n                    if (m) {\n                        applyTransform(p0, p0, m);\n                        applyTransform(p1, p1, m);\n                    }\n\n                    p0[0] = round$4(p0[0] * Z - Z2);\n                    p1[0] = round$4(p1[0] * Z - Z2);\n                    p0[1] = round$4(p0[1] * Z - Z2);\n                    p1[1] = round$4(p1[1] * Z - Z2);\n                    str.push(\n                        // x0, y0\n                        ' m ', p0[0], comma, p0[1],\n                        // x1, y0\n                        ' l ', p1[0], comma, p0[1],\n                        // x1, y1\n                        ' l ', p1[0], comma, p1[1],\n                        // x0, y1\n                        ' l ', p0[0], comma, p1[1]\n                    );\n                    break;\n                case CMD$3.Z:\n                    // FIXME Update xi, yi\n                    str.push(' x ');\n            }\n\n            if (nPoint > 0) {\n                str.push(cmdStr);\n                for (var k = 0; k < nPoint; k++) {\n                    var p = points$3[k];\n\n                    m && applyTransform(p, p, m);\n                    // 不 round 会非常慢\n                    str.push(\n                        round$4(p[0] * Z - Z2), comma, round$4(p[1] * Z - Z2),\n                        k < nPoint - 1 ? comma : ''\n                    );\n                }\n            }\n        }\n\n        return str.join('');\n    };\n\n    // Rewrite the original path method\n    Path.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            vmlEl = createNode('shape');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        updateFillAndStroke(vmlEl, 'fill', style, this);\n        updateFillAndStroke(vmlEl, 'stroke', style, this);\n\n        var m = this.transform;\n        var needTransform = m != null;\n        var strokeEl = vmlEl.getElementsByTagName('stroke')[0];\n        if (strokeEl) {\n            var lineWidth = style.lineWidth;\n            // Get the line scale.\n            // Determinant of this.m_ means how much the area is enlarged by the\n            // transformation. So its square root can be used as a scale factor\n            // for width.\n            if (needTransform && !style.strokeNoScale) {\n                var det = m[0] * m[3] - m[1] * m[2];\n                lineWidth *= sqrt(abs$1(det));\n            }\n            strokeEl.weight = lineWidth + 'px';\n        }\n\n        var path = this.path || (this.path = new PathProxy());\n        if (this.__dirtyPath) {\n            path.beginPath();\n            path.subPixelOptimize = false;\n            this.buildPath(path, this.shape);\n            path.toStatic();\n            this.__dirtyPath = false;\n        }\n\n        vmlEl.path = pathDataToString(path, this.transform);\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Path.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n        this.removeRectText(vmlRoot);\n    };\n\n    Path.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n    /***************************************************\n     * IMAGE\n     **************************************************/\n    var isImage = function (img) {\n        // FIXME img instanceof Image 如果 img 是一个字符串的时候，IE8 下会报错\n        return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';\n        // return img instanceof Image;\n    };\n\n    // Rewrite the original path method\n    ZImage.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        var image = style.image;\n\n        // Image original width, height\n        var ow;\n        var oh;\n\n        if (isImage(image)) {\n            var src = image.src;\n            if (src === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n            else {\n                var imageRuntimeStyle = image.runtimeStyle;\n                var oldRuntimeWidth = imageRuntimeStyle.width;\n                var oldRuntimeHeight = imageRuntimeStyle.height;\n                imageRuntimeStyle.width = 'auto';\n                imageRuntimeStyle.height = 'auto';\n\n                // get the original size\n                ow = image.width;\n                oh = image.height;\n\n                // and remove overides\n                imageRuntimeStyle.width = oldRuntimeWidth;\n                imageRuntimeStyle.height = oldRuntimeHeight;\n\n                // Caching image original width, height and src\n                this._imageSrc = src;\n                this._imageWidth = ow;\n                this._imageHeight = oh;\n            }\n            image = src;\n        }\n        else {\n            if (image === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n        }\n        if (!image) {\n            return;\n        }\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n\n        var dw = style.width;\n        var dh = style.height;\n\n        var sw = style.sWidth;\n        var sh = style.sHeight;\n        var sx = style.sx || 0;\n        var sy = style.sy || 0;\n\n        var hasCrop = sw && sh;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。\n            // vmlEl = vmlCore.createNode('group');\n            vmlEl = doc.createElement('div');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        var vmlElStyle = vmlEl.style;\n        var hasRotation = false;\n        var m;\n        var scaleX = 1;\n        var scaleY = 1;\n        if (this.transform) {\n            m = this.transform;\n            scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);\n            scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);\n\n            hasRotation = m[1] || m[2];\n        }\n        if (hasRotation) {\n            // If filters are necessary (rotation exists), create them\n            // filters are bog-slow, so only create them if abbsolutely necessary\n            // The following check doesn't account for skews (which don't exist\n            // in the canvas spec (yet) anyway.\n            // From excanvas\n            var p0 = [x, y];\n            var p1 = [x + dw, y];\n            var p2 = [x, y + dh];\n            var p3 = [x + dw, y + dh];\n            applyTransform(p0, p0, m);\n            applyTransform(p1, p1, m);\n            applyTransform(p2, p2, m);\n            applyTransform(p3, p3, m);\n\n            var maxX = mathMax$8(p0[0], p1[0], p2[0], p3[0]);\n            var maxY = mathMax$8(p0[1], p1[1], p2[1], p3[1]);\n\n            var transformFilter = [];\n            transformFilter.push('M11=', m[0] / scaleX, comma,\n                        'M12=', m[2] / scaleY, comma,\n                        'M21=', m[1] / scaleX, comma,\n                        'M22=', m[3] / scaleY, comma,\n                        'Dx=', round$4(x * scaleX + m[4]), comma,\n                        'Dy=', round$4(y * scaleY + m[5]));\n\n            vmlElStyle.padding = '0 ' + round$4(maxX) + 'px ' + round$4(maxY) + 'px 0';\n            // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用\n            vmlElStyle.filter = imageTransformPrefix + '.Matrix('\n                + transformFilter.join('') + ', SizingMethod=clip)';\n\n        }\n        else {\n            if (m) {\n                x = x * scaleX + m[4];\n                y = y * scaleY + m[5];\n            }\n            vmlElStyle.filter = '';\n            vmlElStyle.left = round$4(x) + 'px';\n            vmlElStyle.top = round$4(y) + 'px';\n        }\n\n        var imageEl = this._imageEl;\n        var cropEl = this._cropEl;\n\n        if (!imageEl) {\n            imageEl = doc.createElement('div');\n            this._imageEl = imageEl;\n        }\n        var imageELStyle = imageEl.style;\n        if (hasCrop) {\n            // Needs know image original width and height\n            if (!(ow && oh)) {\n                var tmpImage = new Image();\n                var self = this;\n                tmpImage.onload = function () {\n                    tmpImage.onload = null;\n                    ow = tmpImage.width;\n                    oh = tmpImage.height;\n                    // Adjust image width and height to fit the ratio destinationSize / sourceSize\n                    imageELStyle.width = round$4(scaleX * ow * dw / sw) + 'px';\n                    imageELStyle.height = round$4(scaleY * oh * dh / sh) + 'px';\n\n                    // Caching image original width, height and src\n                    self._imageWidth = ow;\n                    self._imageHeight = oh;\n                    self._imageSrc = image;\n                };\n                tmpImage.src = image;\n            }\n            else {\n                imageELStyle.width = round$4(scaleX * ow * dw / sw) + 'px';\n                imageELStyle.height = round$4(scaleY * oh * dh / sh) + 'px';\n            }\n\n            if (!cropEl) {\n                cropEl = doc.createElement('div');\n                cropEl.style.overflow = 'hidden';\n                this._cropEl = cropEl;\n            }\n            var cropElStyle = cropEl.style;\n            cropElStyle.width = round$4((dw + sx * dw / sw) * scaleX);\n            cropElStyle.height = round$4((dh + sy * dh / sh) * scaleY);\n            cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='\n                    + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';\n\n            if (!cropEl.parentNode) {\n                vmlEl.appendChild(cropEl);\n            }\n            if (imageEl.parentNode !== cropEl) {\n                cropEl.appendChild(imageEl);\n            }\n        }\n        else {\n            imageELStyle.width = round$4(scaleX * dw) + 'px';\n            imageELStyle.height = round$4(scaleY * dh) + 'px';\n\n            vmlEl.appendChild(imageEl);\n\n            if (cropEl && cropEl.parentNode) {\n                vmlEl.removeChild(cropEl);\n                this._cropEl = null;\n            }\n        }\n\n        var filterStr = '';\n        var alpha = style.opacity;\n        if (alpha < 1) {\n            filterStr += '.Alpha(opacity=' + round$4(alpha * 100) + ') ';\n        }\n        filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';\n\n        imageELStyle.filter = filterStr;\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n    };\n\n    ZImage.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n\n        this._vmlEl = null;\n        this._cropEl = null;\n        this._imageEl = null;\n\n        this.removeRectText(vmlRoot);\n    };\n\n    ZImage.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n\n    /***************************************************\n     * TEXT\n     **************************************************/\n\n    var DEFAULT_STYLE_NORMAL = 'normal';\n\n    var fontStyleCache = {};\n    var fontStyleCacheCount = 0;\n    var MAX_FONT_CACHE_SIZE = 100;\n    var fontEl = document.createElement('div');\n\n    var getFontStyle = function (fontString) {\n        var fontStyle = fontStyleCache[fontString];\n        if (!fontStyle) {\n            // Clear cache\n            if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {\n                fontStyleCacheCount = 0;\n                fontStyleCache = {};\n            }\n\n            var style = fontEl.style;\n            var fontFamily;\n            try {\n                style.font = fontString;\n                fontFamily = style.fontFamily.split(',')[0];\n            }\n            catch (e) {\n            }\n\n            fontStyle = {\n                style: style.fontStyle || DEFAULT_STYLE_NORMAL,\n                variant: style.fontVariant || DEFAULT_STYLE_NORMAL,\n                weight: style.fontWeight || DEFAULT_STYLE_NORMAL,\n                size: parseFloat(style.fontSize || 12) | 0,\n                family: fontFamily || 'Microsoft YaHei'\n            };\n\n            fontStyleCache[fontString] = fontStyle;\n            fontStyleCacheCount++;\n        }\n        return fontStyle;\n    };\n\n    var textMeasureEl;\n    // Overwrite measure text method\n    $override$1('measureText', function (text, textFont) {\n        var doc$$1 = doc;\n        if (!textMeasureEl) {\n            textMeasureEl = doc$$1.createElement('div');\n            textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'\n                + 'padding:0;margin:0;border:none;white-space:pre;';\n            doc.body.appendChild(textMeasureEl);\n        }\n\n        try {\n            textMeasureEl.style.font = textFont;\n        }\n        catch (ex) {\n            // Ignore failures to set to invalid font.\n        }\n        textMeasureEl.innerHTML = '';\n        // Don't use innerHTML or innerText because they allow markup/whitespace.\n        textMeasureEl.appendChild(doc$$1.createTextNode(text));\n        return {\n            width: textMeasureEl.offsetWidth\n        };\n    });\n\n    var tmpRect$2 = new BoundingRect();\n\n    var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {\n\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n        if (!text) {\n            return;\n        }\n\n        // Convert rich text to plain text. Rich text is not supported in\n        // IE8-, but tags in rich text template will be removed.\n        if (style.rich) {\n            var contentBlock = parseRichText(text, style);\n            text = [];\n            for (var i = 0; i < contentBlock.lines.length; i++) {\n                var tokens = contentBlock.lines[i].tokens;\n                var textLine = [];\n                for (var j = 0; j < tokens.length; j++) {\n                    textLine.push(tokens[j].text);\n                }\n                text.push(textLine.join(''));\n            }\n            text = text.join('\\n');\n        }\n\n        var x;\n        var y;\n        var align = style.textAlign;\n        var verticalAlign = style.textVerticalAlign;\n\n        var fontStyle = getFontStyle(style.font);\n        // FIXME encodeHtmlAttribute ?\n        var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '\n            + fontStyle.size + 'px \"' + fontStyle.family + '\"';\n\n        textRect = textRect || getBoundingRect(text, font, align, verticalAlign, style.textPadding, style.textLineHeight);\n\n        // Transform rect to view space\n        var m = this.transform;\n        // Ignore transform for text in other element\n        if (m && !fromTextEl) {\n            tmpRect$2.copy(rect);\n            tmpRect$2.applyTransform(m);\n            rect = tmpRect$2;\n        }\n\n        if (!fromTextEl) {\n            var textPosition = style.textPosition;\n            var distance$$1 = style.textDistance;\n            // Text position represented by coord\n            if (textPosition instanceof Array) {\n                x = rect.x + parsePercent$3(textPosition[0], rect.width);\n                y = rect.y + parsePercent$3(textPosition[1], rect.height);\n\n                align = align || 'left';\n            }\n            else {\n                var res = adjustTextPositionOnRect(\n                    textPosition, rect, distance$$1\n                );\n                x = res.x;\n                y = res.y;\n\n                // Default align and baseline when has textPosition\n                align = align || res.textAlign;\n                verticalAlign = verticalAlign || res.textVerticalAlign;\n            }\n        }\n        else {\n            x = rect.x;\n            y = rect.y;\n        }\n\n        x = adjustTextX(x, textRect.width, align);\n        y = adjustTextY(y, textRect.height, verticalAlign);\n\n        // Force baseline 'middle'\n        y += textRect.height / 2;\n\n        // var fontSize = fontStyle.size;\n        // 1.75 is an arbitrary number, as there is no info about the text baseline\n        // switch (baseline) {\n            // case 'hanging':\n            // case 'top':\n            //     y += fontSize / 1.75;\n            //     break;\n        //     case 'middle':\n        //         break;\n        //     default:\n        //     // case null:\n        //     // case 'alphabetic':\n        //     // case 'ideographic':\n        //     // case 'bottom':\n        //         y -= fontSize / 2.25;\n        //         break;\n        // }\n\n        // switch (align) {\n        //     case 'left':\n        //         break;\n        //     case 'center':\n        //         x -= textRect.width / 2;\n        //         break;\n        //     case 'right':\n        //         x -= textRect.width;\n        //         break;\n            // case 'end':\n                // align = elementStyle.direction == 'ltr' ? 'right' : 'left';\n                // break;\n            // case 'start':\n                // align = elementStyle.direction == 'rtl' ? 'right' : 'left';\n                // break;\n            // default:\n            //     align = 'left';\n        // }\n\n        var createNode$$1 = createNode;\n\n        var textVmlEl = this._textVmlEl;\n        var pathEl;\n        var textPathEl;\n        var skewEl;\n        if (!textVmlEl) {\n            textVmlEl = createNode$$1('line');\n            pathEl = createNode$$1('path');\n            textPathEl = createNode$$1('textpath');\n            skewEl = createNode$$1('skew');\n\n            // FIXME Why here is not cammel case\n            // Align 'center' seems wrong\n            textPathEl.style['v-text-align'] = 'left';\n\n            initRootElStyle(textVmlEl);\n\n            pathEl.textpathok = true;\n            textPathEl.on = true;\n\n            textVmlEl.from = '0 0';\n            textVmlEl.to = '1000 0.05';\n\n            append(textVmlEl, skewEl);\n            append(textVmlEl, pathEl);\n            append(textVmlEl, textPathEl);\n\n            this._textVmlEl = textVmlEl;\n        }\n        else {\n            // 这里是在前面 appendChild 保证顺序的前提下\n            skewEl = textVmlEl.firstChild;\n            pathEl = skewEl.nextSibling;\n            textPathEl = pathEl.nextSibling;\n        }\n\n        var coords = [x, y];\n        var textVmlElStyle = textVmlEl.style;\n        // Ignore transform for text in other element\n        if (m && fromTextEl) {\n            applyTransform(coords, coords, m);\n\n            skewEl.on = true;\n\n            skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma\n                            + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';\n\n            // Text position\n            skewEl.offset = (round$4(coords[0]) || 0) + ',' + (round$4(coords[1]) || 0);\n            // Left top point as origin\n            skewEl.origin = '0 0';\n\n            textVmlElStyle.left = '0px';\n            textVmlElStyle.top = '0px';\n        }\n        else {\n            skewEl.on = false;\n            textVmlElStyle.left = round$4(x) + 'px';\n            textVmlElStyle.top = round$4(y) + 'px';\n        }\n\n        textPathEl.string = encodeHtmlAttribute(text);\n        // TODO\n        try {\n            textPathEl.style.font = font;\n        }\n        // Error font format\n        catch (e) {}\n\n        updateFillAndStroke(textVmlEl, 'fill', {\n            fill: style.textFill,\n            opacity: style.opacity\n        }, this);\n        updateFillAndStroke(textVmlEl, 'stroke', {\n            stroke: style.textStroke,\n            opacity: style.opacity,\n            lineDash: style.lineDash\n        }, this);\n\n        textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Attached to root\n        append(vmlRoot, textVmlEl);\n    };\n\n    var removeRectText = function (vmlRoot) {\n        remove(vmlRoot, this._textVmlEl);\n        this._textVmlEl = null;\n    };\n\n    var appendRectText = function (vmlRoot) {\n        append(vmlRoot, this._textVmlEl);\n    };\n\n    var list = [RectText, Displayable, ZImage, Path, Text];\n\n    // In case Displayable has been mixed in RectText\n    for (var i$3 = 0; i$3 < list.length; i$3++) {\n        var proto$8 = list[i$3].prototype;\n        proto$8.drawRectText = drawRectText;\n        proto$8.removeRectText = removeRectText;\n        proto$8.appendRectText = appendRectText;\n    }\n\n    Text.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, {\n                x: style.x || 0, y: style.y || 0,\n                width: 0, height: 0\n            }, this.getBoundingRect(), true);\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Text.prototype.onRemove = function (vmlRoot) {\n        this.removeRectText(vmlRoot);\n    };\n\n    Text.prototype.onAdd = function (vmlRoot) {\n        this.appendRectText(vmlRoot);\n    };\n}\n\n/**\n * VML Painter.\n *\n * @module zrender/vml/Painter\n */\n\nfunction parseInt10$1(val) {\n    return parseInt(val, 10);\n}\n\n/**\n * @alias module:zrender/vml/Painter\n */\nfunction VMLPainter(root, storage) {\n\n    initVML();\n\n    this.root = root;\n\n    this.storage = storage;\n\n    var vmlViewport = document.createElement('div');\n\n    var vmlRoot = document.createElement('div');\n\n    vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';\n\n    vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';\n\n    root.appendChild(vmlViewport);\n\n    this._vmlRoot = vmlRoot;\n    this._vmlViewport = vmlViewport;\n\n    this.resize();\n\n    // Modify storage\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        if (el) {\n            el.onRemove && el.onRemove(vmlRoot);\n        }\n    };\n\n    storage.addToStorage = function (el) {\n        // Displayable already has a vml node\n        el.onAdd && el.onAdd(vmlRoot);\n\n        oldAddToStorage.call(storage, el);\n    };\n\n    this._firstPaint = true;\n}\n\nVMLPainter.prototype = {\n\n    constructor: VMLPainter,\n\n    getType: function () {\n        return 'vml';\n    },\n\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._vmlViewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     */\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true, true);\n\n        this._paintList(list);\n    },\n\n    _paintList: function (list) {\n        var vmlRoot = this._vmlRoot;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            if (el.invisible || el.ignore) {\n                if (!el.__alreadyNotVisible) {\n                    el.onRemove(vmlRoot);\n                }\n                // Set as already invisible\n                el.__alreadyNotVisible = true;\n            }\n            else {\n                if (el.__alreadyNotVisible) {\n                    el.onAdd(vmlRoot);\n                }\n                el.__alreadyNotVisible = false;\n                if (el.__dirty) {\n                    el.beforeBrush && el.beforeBrush();\n                    (el.brushVML || el.brush).call(el, vmlRoot);\n                    el.afterBrush && el.afterBrush();\n                }\n            }\n            el.__dirty = false;\n        }\n\n        if (this._firstPaint) {\n            // Detached from document at first time\n            // to avoid page refreshing too many times\n\n            // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变\n            this._vmlViewport.appendChild(vmlRoot);\n            this._firstPaint = false;\n        }\n    },\n\n    resize: function (width, height) {\n        var width = width == null ? this._getWidth() : width;\n        var height = height == null ? this._getHeight() : height;\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var vmlViewportStyle = this._vmlViewport.style;\n            vmlViewportStyle.width = width + 'px';\n            vmlViewportStyle.height = height + 'px';\n        }\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._vmlRoot =\n        this._vmlViewport =\n        this.storage = null;\n    },\n\n    getWidth: function () {\n        return this._width;\n    },\n\n    getHeight: function () {\n        return this._height;\n    },\n\n    clear: function () {\n        if (this._vmlViewport) {\n            this.root.removeChild(this._vmlViewport);\n        }\n    },\n\n    _getWidth: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientWidth || parseInt10$1(stl.width))\n                - parseInt10$1(stl.paddingLeft)\n                - parseInt10$1(stl.paddingRight)) | 0;\n    },\n\n    _getHeight: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientHeight || parseInt10$1(stl.height))\n                - parseInt10$1(stl.paddingTop)\n                - parseInt10$1(stl.paddingBottom)) | 0;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport(method) {\n    return function () {\n        zrLog('In IE8.0 VML mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsupported methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers',\n    'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'\n], function (name) {\n    VMLPainter.prototype[name] = createMethodNotSupport(name);\n});\n\nregisterPainter('vml', VMLPainter);\n\nvar svgURI = 'http://www.w3.org/2000/svg';\n\nfunction createElement(name) {\n    return document.createElementNS(svgURI, name);\n}\n\n// TODO\n// 1. shadow\n// 2. Image: sx, sy, sw, sh\n\nvar CMD$4 = PathProxy.CMD;\nvar arrayJoin = Array.prototype.join;\n\nvar NONE = 'none';\nvar mathRound = Math.round;\nvar mathSin$3 = Math.sin;\nvar mathCos$3 = Math.cos;\nvar PI$5 = Math.PI;\nvar PI2$7 = Math.PI * 2;\nvar degree = 180 / PI$5;\n\nvar EPSILON$4 = 1e-4;\n\nfunction round4(val) {\n    return mathRound(val * 1e4) / 1e4;\n}\n\nfunction isAroundZero$1(val) {\n    return val < EPSILON$4 && val > -EPSILON$4;\n}\n\nfunction pathHasFill(style, isText) {\n    var fill = isText ? style.textFill : style.fill;\n    return fill != null && fill !== NONE;\n}\n\nfunction pathHasStroke(style, isText) {\n    var stroke = isText ? style.textStroke : style.stroke;\n    return stroke != null && stroke !== NONE;\n}\n\nfunction setTransform(svgEl, m) {\n    if (m) {\n        attr(svgEl, 'transform', 'matrix(' + arrayJoin.call(m, ',') + ')');\n    }\n}\n\nfunction attr(el, key, val) {\n    if (!val || val.type !== 'linear' && val.type !== 'radial') {\n        // Don't set attribute for gradient, since it need new dom nodes\n        el.setAttribute(key, val);\n    }\n}\n\nfunction attrXLink(el, key, val) {\n    el.setAttributeNS('http://www.w3.org/1999/xlink', key, val);\n}\n\nfunction bindStyle(svgEl, style, isText, el) {\n    if (pathHasFill(style, isText)) {\n        var fill = isText ? style.textFill : style.fill;\n        fill = fill === 'transparent' ? NONE : fill;\n\n        /**\n         * FIXME:\n         * This is a temporary fix for Chrome's clipping bug\n         * that happens when a clip-path is referring another one.\n         * This fix should be used before Chrome's bug is fixed.\n         * For an element that has clip-path, and fill is none,\n         * set it to be \"rgba(0, 0, 0, 0.002)\" will hide the element.\n         * Otherwise, it will show black fill color.\n         * 0.002 is used because this won't work for alpha values smaller\n         * than 0.002.\n         *\n         * See\n         * https://bugs.chromium.org/p/chromium/issues/detail?id=659790\n         * for more information.\n         */\n        if (svgEl.getAttribute('clip-path') !== 'none' && fill === NONE) {\n            fill = 'rgba(0, 0, 0, 0.002)';\n        }\n\n        attr(svgEl, 'fill', fill);\n        attr(svgEl, 'fill-opacity', style.fillOpacity != null ? style.fillOpacity * style.opacity : style.opacity);\n    }\n    else {\n        attr(svgEl, 'fill', NONE);\n    }\n\n    if (pathHasStroke(style, isText)) {\n        var stroke = isText ? style.textStroke : style.stroke;\n        stroke = stroke === 'transparent' ? NONE : stroke;\n        attr(svgEl, 'stroke', stroke);\n        var strokeWidth = isText\n            ? style.textStrokeWidth\n            : style.lineWidth;\n        var strokeScale = !isText && style.strokeNoScale\n            ? el.getLineScale()\n            : 1;\n        attr(svgEl, 'stroke-width', strokeWidth / strokeScale);\n        // stroke then fill for text; fill then stroke for others\n        attr(svgEl, 'paint-order', isText ? 'stroke' : 'fill');\n        attr(svgEl, 'stroke-opacity', style.strokeOpacity != null ? style.strokeOpacity : style.opacity);\n        var lineDash = style.lineDash;\n        if (lineDash) {\n            attr(svgEl, 'stroke-dasharray', style.lineDash.join(','));\n            attr(svgEl, 'stroke-dashoffset', mathRound(style.lineDashOffset || 0));\n        }\n        else {\n            attr(svgEl, 'stroke-dasharray', '');\n        }\n\n        // PENDING\n        style.lineCap && attr(svgEl, 'stroke-linecap', style.lineCap);\n        style.lineJoin && attr(svgEl, 'stroke-linejoin', style.lineJoin);\n        style.miterLimit && attr(svgEl, 'stroke-miterlimit', style.miterLimit);\n    }\n    else {\n        attr(svgEl, 'stroke', NONE);\n    }\n}\n\n/***************************************************\n * PATH\n **************************************************/\nfunction pathDataToString$1(path) {\n    var str = [];\n    var data = path.data;\n    var dataLength = path.len();\n    for (var i = 0; i < dataLength;) {\n        var cmd = data[i++];\n        var cmdStr = '';\n        var nData = 0;\n        switch (cmd) {\n            case CMD$4.M:\n                cmdStr = 'M';\n                nData = 2;\n                break;\n            case CMD$4.L:\n                cmdStr = 'L';\n                nData = 2;\n                break;\n            case CMD$4.Q:\n                cmdStr = 'Q';\n                nData = 4;\n                break;\n            case CMD$4.C:\n                cmdStr = 'C';\n                nData = 6;\n                break;\n            case CMD$4.A:\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                var psi = data[i++];\n                var clockwise = data[i++];\n\n                var dThetaPositive = Math.abs(dTheta);\n                var isCircle = isAroundZero$1(dThetaPositive - PI2$7)\n                    && !isAroundZero$1(dThetaPositive);\n\n                var large = false;\n                if (dThetaPositive >= PI2$7) {\n                    large = true;\n                }\n                else if (isAroundZero$1(dThetaPositive)) {\n                    large = false;\n                }\n                else {\n                    large = (dTheta > -PI$5 && dTheta < 0 || dTheta > PI$5)\n                        === !!clockwise;\n                }\n\n                var x0 = round4(cx + rx * mathCos$3(theta));\n                var y0 = round4(cy + ry * mathSin$3(theta));\n\n                // It will not draw if start point and end point are exactly the same\n                // We need to shift the end point with a small value\n                // FIXME A better way to draw circle ?\n                if (isCircle) {\n                    if (clockwise) {\n                        dTheta = PI2$7 - 1e-4;\n                    }\n                    else {\n                        dTheta = -PI2$7 + 1e-4;\n                    }\n\n                    large = true;\n\n                    if (i === 9) {\n                        // Move to (x0, y0) only when CMD.A comes at the\n                        // first position of a shape.\n                        // For instance, when drawing a ring, CMD.A comes\n                        // after CMD.M, so it's unnecessary to move to\n                        // (x0, y0).\n                        str.push('M', x0, y0);\n                    }\n                }\n\n                var x = round4(cx + rx * mathCos$3(theta + dTheta));\n                var y = round4(cy + ry * mathSin$3(theta + dTheta));\n\n                // FIXME Ellipse\n                str.push('A', round4(rx), round4(ry),\n                    mathRound(psi * degree), +large, +clockwise, x, y);\n                break;\n            case CMD$4.Z:\n                cmdStr = 'Z';\n                break;\n            case CMD$4.R:\n                var x = round4(data[i++]);\n                var y = round4(data[i++]);\n                var w = round4(data[i++]);\n                var h = round4(data[i++]);\n                str.push(\n                    'M', x, y,\n                    'L', x + w, y,\n                    'L', x + w, y + h,\n                    'L', x, y + h,\n                    'L', x, y\n                );\n                break;\n        }\n        cmdStr && str.push(cmdStr);\n        for (var j = 0; j < nData; j++) {\n            // PENDING With scale\n            str.push(round4(data[i++]));\n        }\n    }\n    return str.join(' ');\n}\n\nvar svgPath = {};\nsvgPath.brush = function (el) {\n    var style = el.style;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('path');\n        el.__svgEl = svgEl;\n    }\n\n    if (!el.path) {\n        el.createPathProxy();\n    }\n    var path = el.path;\n\n    if (el.__dirtyPath) {\n        path.beginPath();\n        path.subPixelOptimize = false;\n        el.buildPath(path, el.shape);\n        el.__dirtyPath = false;\n\n        var pathStr = pathDataToString$1(path);\n        if (pathStr.indexOf('NaN') < 0) {\n            // Ignore illegal path, which may happen such in out-of-range\n            // data in Calendar series.\n            attr(svgEl, 'd', pathStr);\n        }\n    }\n\n    bindStyle(svgEl, style, false, el);\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * IMAGE\n **************************************************/\nvar svgImage = {};\nsvgImage.brush = function (el) {\n    var style = el.style;\n    var image = style.image;\n\n    if (image instanceof HTMLImageElement) {\n        var src = image.src;\n        image = src;\n    }\n    if (!image) {\n        return;\n    }\n\n    var x = style.x || 0;\n    var y = style.y || 0;\n\n    var dw = style.width;\n    var dh = style.height;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('image');\n        el.__svgEl = svgEl;\n    }\n\n    if (image !== el.__imageSrc) {\n        attrXLink(svgEl, 'href', image);\n        // Caching image src\n        el.__imageSrc = image;\n    }\n\n    attr(svgEl, 'width', dw);\n    attr(svgEl, 'height', dh);\n\n    attr(svgEl, 'x', x);\n    attr(svgEl, 'y', y);\n\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * TEXT\n **************************************************/\nvar svgText = {};\nvar tmpRect$3 = new BoundingRect();\n\nvar svgTextDrawRectText = function (el, rect, textRect) {\n    var style = el.style;\n\n    el.__dirty && normalizeTextStyle(style, true);\n\n    var text = style.text;\n    // Convert to string\n    if (text == null) {\n        // Draw no text only when text is set to null, but not ''\n        return;\n    }\n    else {\n        text += '';\n    }\n\n    var textSvgEl = el.__textSvgEl;\n    if (!textSvgEl) {\n        textSvgEl = createElement('text');\n        el.__textSvgEl = textSvgEl;\n    }\n\n    var x;\n    var y;\n    var textPosition = style.textPosition;\n    var distance = style.textDistance;\n    var align = style.textAlign || 'left';\n\n    if (typeof style.fontSize === 'number') {\n        style.fontSize += 'px';\n    }\n    var font = style.font\n        || [\n            style.fontStyle || '',\n            style.fontWeight || '',\n            style.fontSize || '',\n            style.fontFamily || ''\n        ].join(' ')\n        || DEFAULT_FONT$1;\n\n    var verticalAlign = getVerticalAlignForSvg(style.textVerticalAlign);\n\n    textRect = getBoundingRect(text, font, align,\n        verticalAlign, style.textPadding, style.textLineHeight);\n\n    var lineHeight = textRect.lineHeight;\n    // Text position represented by coord\n    if (textPosition instanceof Array) {\n        x = rect.x + textPosition[0];\n        y = rect.y + textPosition[1];\n    }\n    else {\n        var newPos = adjustTextPositionOnRect(\n            textPosition, rect, distance\n        );\n        x = newPos.x;\n        y = newPos.y;\n        verticalAlign = getVerticalAlignForSvg(newPos.textVerticalAlign);\n        align = newPos.textAlign;\n    }\n\n    attr(textSvgEl, 'alignment-baseline', verticalAlign);\n\n    if (font) {\n        textSvgEl.style.font = font;\n    }\n\n    var textPadding = style.textPadding;\n\n    // Make baseline top\n    attr(textSvgEl, 'x', x);\n    attr(textSvgEl, 'y', y);\n\n    bindStyle(textSvgEl, style, true, el);\n    if (el instanceof Text || el.style.transformText) {\n        // Transform text with element\n        setTransform(textSvgEl, el.transform);\n    }\n    else {\n        if (el.transform) {\n            tmpRect$3.copy(rect);\n            tmpRect$3.applyTransform(el.transform);\n            rect = tmpRect$3;\n        }\n        else {\n            var pos = el.transformCoordToGlobal(rect.x, rect.y);\n            rect.x = pos[0];\n            rect.y = pos[1];\n            el.transform = identity(create$1());\n        }\n\n        // Text rotation, but no element transform\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = textRect.width / 2 + x;\n            y = textRect.height / 2 + y;\n        }\n        else if (origin) {\n            x = origin[0] + x;\n            y = origin[1] + y;\n        }\n        var rotate$$1 = -style.textRotation || 0;\n        var transform = create$1();\n        // Apply textRotate to element matrix\n        rotate(transform, transform, rotate$$1);\n\n        var pos = [el.transform[4], el.transform[5]];\n        translate(transform, transform, pos);\n        setTransform(textSvgEl, transform);\n    }\n\n    var textLines = text.split('\\n');\n    var nTextLines = textLines.length;\n    var textAnchor = align;\n    // PENDING\n    if (textAnchor === 'left') {\n        textAnchor = 'start';\n        textPadding && (x += textPadding[3]);\n    }\n    else if (textAnchor === 'right') {\n        textAnchor = 'end';\n        textPadding && (x -= textPadding[1]);\n    }\n    else if (textAnchor === 'center') {\n        textAnchor = 'middle';\n        textPadding && (x += (textPadding[3] - textPadding[1]) / 2);\n    }\n\n    var dy = 0;\n    if (verticalAlign === 'after-edge') {\n        dy = -textRect.height + lineHeight;\n        textPadding && (dy -= textPadding[2]);\n    }\n    else if (verticalAlign === 'middle') {\n        dy = (-textRect.height + lineHeight) / 2;\n        textPadding && (y += (textPadding[0] - textPadding[2]) / 2);\n    }\n    else {\n        textPadding && (dy += textPadding[0]);\n    }\n\n    // Font may affect position of each tspan elements\n    if (el.__text !== text || el.__textFont !== font) {\n        var tspanList = el.__tspanList || [];\n        el.__tspanList = tspanList;\n        for (var i = 0; i < nTextLines; i++) {\n            // Using cached tspan elements\n            var tspan = tspanList[i];\n            if (!tspan) {\n                tspan = tspanList[i] = createElement('tspan');\n                textSvgEl.appendChild(tspan);\n                attr(tspan, 'alignment-baseline', verticalAlign);\n                attr(tspan, 'text-anchor', textAnchor);\n            }\n            else {\n                tspan.innerHTML = '';\n            }\n            attr(tspan, 'x', x);\n            attr(tspan, 'y', y + i * lineHeight + dy);\n            tspan.appendChild(document.createTextNode(textLines[i]));\n        }\n        // Remove unsed tspan elements\n        for (; i < tspanList.length; i++) {\n            textSvgEl.removeChild(tspanList[i]);\n        }\n        tspanList.length = nTextLines;\n\n        el.__text = text;\n        el.__textFont = font;\n    }\n    else if (el.__tspanList.length) {\n        // Update span x and y\n        var len = el.__tspanList.length;\n        for (var i = 0; i < len; ++i) {\n            var tspan = el.__tspanList[i];\n            if (tspan) {\n                attr(tspan, 'x', x);\n                attr(tspan, 'y', y + i * lineHeight + dy);\n            }\n        }\n    }\n};\n\nfunction getVerticalAlignForSvg(verticalAlign) {\n    if (verticalAlign === 'middle') {\n        return 'middle';\n    }\n    else if (verticalAlign === 'bottom') {\n        return 'after-edge';\n    }\n    else {\n        return 'hanging';\n    }\n}\n\nsvgText.drawRectText = svgTextDrawRectText;\n\nsvgText.brush = function (el) {\n    var style = el.style;\n    if (style.text != null) {\n        // 强制设置 textPosition\n        style.textPosition = [0, 0];\n        svgTextDrawRectText(el, {\n            x: style.x || 0, y: style.y || 0,\n            width: 0, height: 0\n        }, el.getBoundingRect());\n    }\n};\n\n// Myers' Diff Algorithm\n// Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.js\n\nfunction Diff() {}\n\nDiff.prototype = {\n    diff: function (oldArr, newArr, equals) {\n        if (!equals) {\n            equals = function (a, b) {\n                return a === b;\n            };\n        }\n        this.equals = equals;\n\n        var self = this;\n\n        oldArr = oldArr.slice();\n        newArr = newArr.slice();\n        // Allow subclasses to massage the input prior to running\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var editLength = 1;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0, i.e. the content starts with the same values\n        var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);\n        if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n            var indices = [];\n            for (var i = 0; i < newArr.length; i++) {\n                indices.push(i);\n            }\n            // Identity per the equality and tokenizer\n            return [{\n                indices: indices, count: newArr.length\n            }];\n        }\n\n        // Main worker method. checks all permutations of a given edit length for acceptance.\n        function execEditLength() {\n            for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {\n                var basePath;\n                var addPath = bestPath[diagonalPath - 1];\n                var removePath = bestPath[diagonalPath + 1];\n                var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n                if (addPath) {\n                    // No one else is going to attempt to use this value, clear it\n                    bestPath[diagonalPath - 1] = undefined;\n                }\n\n                var canAdd = addPath && addPath.newPos + 1 < newLen;\n                var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n                if (!canAdd && !canRemove) {\n                    // If this path is a terminal then prune\n                    bestPath[diagonalPath] = undefined;\n                    continue;\n                }\n\n                // Select the diagonal that we want to branch from. We select the prior\n                // path whose position in the new string is the farthest from the origin\n                // and does not pass the bounds of the diff graph\n                if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n                    basePath = clonePath(removePath);\n                    self.pushComponent(basePath.components, undefined, true);\n                }\n                else {\n                    basePath = addPath;   // No need to clone, we've pulled it from the list\n                    basePath.newPos++;\n                    self.pushComponent(basePath.components, true, undefined);\n                }\n\n                oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath);\n\n                // If we have hit the end of both strings, then we are done\n                if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n                    return buildValues(self, basePath.components, newArr, oldArr);\n                }\n                else {\n                    // Otherwise track this path as a potential candidate and continue.\n                    bestPath[diagonalPath] = basePath;\n                }\n            }\n\n            editLength++;\n        }\n\n        while (editLength <= maxEditLength) {\n            var ret = execEditLength();\n            if (ret) {\n                return ret;\n            }\n        }\n    },\n\n    pushComponent: function (components, added, removed) {\n        var last = components[components.length - 1];\n        if (last && last.added === added && last.removed === removed) {\n            // We need to clone here as the component clone operation is just\n            // as shallow array clone\n            components[components.length - 1] = {count: last.count + 1, added: added, removed: removed };\n        }\n        else {\n            components.push({count: 1, added: added, removed: removed });\n        }\n    },\n    extractCommon: function (basePath, newArr, oldArr, diagonalPath) {\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var newPos = basePath.newPos;\n        var oldPos = newPos - diagonalPath;\n        var commonCount = 0;\n\n        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {\n            newPos++;\n            oldPos++;\n            commonCount++;\n        }\n\n        if (commonCount) {\n            basePath.components.push({count: commonCount});\n        }\n\n        basePath.newPos = newPos;\n        return oldPos;\n    },\n    tokenize: function (value) {\n        return value.slice();\n    },\n    join: function (value) {\n        return value.slice();\n    }\n};\n\nfunction buildValues(diff, components, newArr, oldArr) {\n    var componentPos = 0;\n    var componentLen = components.length;\n    var newPos = 0;\n    var oldPos = 0;\n\n    for (; componentPos < componentLen; componentPos++) {\n        var component = components[componentPos];\n        if (!component.removed) {\n            var indices = [];\n            for (var i = newPos; i < newPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            newPos += component.count;\n            // Common case\n            if (!component.added) {\n                oldPos += component.count;\n            }\n        }\n        else {\n            var indices = [];\n            for (var i = oldPos; i < oldPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            oldPos += component.count;\n        }\n    }\n\n    return components;\n}\n\nfunction clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n}\n\nvar arrayDiff = new Diff();\n\nvar arrayDiff$1 = function (oldArr, newArr, callback) {\n    return arrayDiff.diff(oldArr, newArr, callback);\n};\n\n/**\n * @file Manages elements that can be defined in <defs> in SVG,\n *       e.g., gradients, clip path, etc.\n * @author Zhang Wenli\n */\n\nvar MARK_UNUSED = '0';\nvar MARK_USED = '1';\n\n/**\n * Manages elements that can be defined in <defs> in SVG,\n * e.g., gradients, clip path, etc.\n *\n * @class\n * @param {number}          zrId      zrender instance id\n * @param {SVGElement}      svgRoot   root of SVG document\n * @param {string|string[]} tagNames  possible tag names\n * @param {string}          markLabel label name to make if the element\n *                                    is used\n */\nfunction Definable(\n    zrId,\n    svgRoot,\n    tagNames,\n    markLabel,\n    domName\n) {\n    this._zrId = zrId;\n    this._svgRoot = svgRoot;\n    this._tagNames = typeof tagNames === 'string' ? [tagNames] : tagNames;\n    this._markLabel = markLabel;\n    this._domName = domName || '_dom';\n\n    this.nextId = 0;\n}\n\n\nDefinable.prototype.createElement = createElement;\n\n\n/**\n * Get the <defs> tag for svgRoot; optionally creates one if not exists.\n *\n * @param {boolean} isForceCreating if need to create when not exists\n * @return {SVGDefsElement} SVG <defs> element, null if it doesn't\n * exist and isForceCreating is false\n */\nDefinable.prototype.getDefs = function (isForceCreating) {\n    var svgRoot = this._svgRoot;\n    var defs = this._svgRoot.getElementsByTagName('defs');\n    if (defs.length === 0) {\n        // Not exist\n        if (isForceCreating) {\n            defs = svgRoot.insertBefore(\n                this.createElement('defs'), // Create new tag\n                svgRoot.firstChild // Insert in the front of svg\n            );\n            if (!defs.contains) {\n                // IE doesn't support contains method\n                defs.contains = function (el) {\n                    var children = defs.children;\n                    if (!children) {\n                        return false;\n                    }\n                    for (var i = children.length - 1; i >= 0; --i) {\n                        if (children[i] === el) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n            }\n            return defs;\n        }\n        else {\n            return null;\n        }\n    }\n    else {\n        return defs[0];\n    }\n};\n\n\n/**\n * Update DOM element if necessary.\n *\n * @param {Object|string} element style element. e.g., for gradient,\n *                                it may be '#ccc' or {type: 'linear', ...}\n * @param {Function|undefined} onUpdate update callback\n */\nDefinable.prototype.update = function (element, onUpdate) {\n    if (!element) {\n        return;\n    }\n\n    var defs = this.getDefs(false);\n    if (element[this._domName] && defs.contains(element[this._domName])) {\n        // Update DOM\n        if (typeof onUpdate === 'function') {\n            onUpdate(element);\n        }\n    }\n    else {\n        // No previous dom, create new\n        var dom = this.add(element);\n        if (dom) {\n            element[this._domName] = dom;\n        }\n    }\n};\n\n\n/**\n * Add gradient dom to defs\n *\n * @param {SVGElement} dom DOM to be added to <defs>\n */\nDefinable.prototype.addDom = function (dom) {\n    var defs = this.getDefs(true);\n    defs.appendChild(dom);\n};\n\n\n/**\n * Remove DOM of a given element.\n *\n * @param {SVGElement} element element to remove dom\n */\nDefinable.prototype.removeDom = function (element) {\n    var defs = this.getDefs(false);\n    if (defs && element[this._domName]) {\n        defs.removeChild(element[this._domName]);\n        element[this._domName] = null;\n    }\n};\n\n\n/**\n * Get DOMs of this element.\n *\n * @return {HTMLDomElement} doms of this defineable elements in <defs>\n */\nDefinable.prototype.getDoms = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // No dom when defs is not defined\n        return [];\n    }\n\n    var doms = [];\n    each$1(this._tagNames, function (tagName) {\n        var tags = defs.getElementsByTagName(tagName);\n        // Note that tags is HTMLCollection, which is array-like\n        // rather than real array.\n        // So `doms.concat(tags)` add tags as one object.\n        doms = doms.concat([].slice.call(tags));\n    });\n\n    return doms;\n};\n\n\n/**\n * Mark DOMs to be unused before painting, and clear unused ones at the end\n * of the painting.\n */\nDefinable.prototype.markAllUnused = function () {\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        dom[that._markLabel] = MARK_UNUSED;\n    });\n};\n\n\n/**\n * Mark a single DOM to be used.\n *\n * @param {SVGElement} dom DOM to mark\n */\nDefinable.prototype.markUsed = function (dom) {\n    if (dom) {\n        dom[this._markLabel] = MARK_USED;\n    }\n};\n\n\n/**\n * Remove unused DOMs defined in <defs>\n */\nDefinable.prototype.removeUnused = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // Nothing to remove\n        return;\n    }\n\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        if (dom[that._markLabel] !== MARK_USED) {\n            // Remove gradient\n            defs.removeChild(dom);\n        }\n    });\n};\n\n\n/**\n * Get SVG proxy.\n *\n * @param {Displayable} displayable displayable element\n * @return {Path|Image|Text} svg proxy of given element\n */\nDefinable.prototype.getSvgProxy = function (displayable) {\n    if (displayable instanceof Path) {\n        return svgPath;\n    }\n    else if (displayable instanceof ZImage) {\n        return svgImage;\n    }\n    else if (displayable instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n};\n\n\n/**\n * Get text SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element of text\n */\nDefinable.prototype.getTextSvgElement = function (displayable) {\n    return displayable.__textSvgEl;\n};\n\n\n/**\n * Get SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element\n */\nDefinable.prototype.getSvgElement = function (displayable) {\n    return displayable.__svgEl;\n};\n\n/**\n * @file Manages SVG gradient elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG gradient elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction GradientManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['linearGradient', 'radialGradient'],\n        '__gradient_in_use__'\n    );\n}\n\n\ninherits(GradientManager, Definable);\n\n\n/**\n * Create new gradient DOM for fill or stroke if not exist,\n * but will not update gradient if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nGradientManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && displayable.style) {\n        var that = this;\n        each$1(['fill', 'stroke'], function (fillOrStroke) {\n            if (displayable.style[fillOrStroke]\n                && (displayable.style[fillOrStroke].type === 'linear'\n                || displayable.style[fillOrStroke].type === 'radial')\n            ) {\n                var gradient = displayable.style[fillOrStroke];\n                var defs = that.getDefs(true);\n\n                // Create dom in <defs> if not exists\n                var dom;\n                if (gradient._dom) {\n                    // Gradient exists\n                    dom = gradient._dom;\n                    if (!defs.contains(gradient._dom)) {\n                        // _dom is no longer in defs, recreate\n                        that.addDom(dom);\n                    }\n                }\n                else {\n                    // New dom\n                    dom = that.add(gradient);\n                }\n\n                that.markUsed(displayable);\n\n                var id = dom.getAttribute('id');\n                svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');\n            }\n        });\n    }\n};\n\n\n/**\n * Add a new gradient tag in <defs>\n *\n * @param   {Gradient} gradient zr gradient instance\n * @return {SVGLinearGradientElement | SVGRadialGradientElement}\n *                            created DOM\n */\nGradientManager.prototype.add = function (gradient) {\n    var dom;\n    if (gradient.type === 'linear') {\n        dom = this.createElement('linearGradient');\n    }\n    else if (gradient.type === 'radial') {\n        dom = this.createElement('radialGradient');\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return null;\n    }\n\n    // Set dom id with gradient id, since each gradient instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    gradient.id = gradient.id || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-gradient-' + gradient.id);\n\n    this.updateDom(gradient, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update gradient.\n *\n * @param {Gradient} gradient zr gradient instance\n */\nGradientManager.prototype.update = function (gradient) {\n    var that = this;\n    Definable.prototype.update.call(this, gradient, function () {\n        var type = gradient.type;\n        var tagName = gradient._dom.tagName;\n        if (type === 'linear' && tagName === 'linearGradient'\n            || type === 'radial' && tagName === 'radialGradient'\n        ) {\n            // Gradient type is not changed, update gradient\n            that.updateDom(gradient, gradient._dom);\n        }\n        else {\n            // Remove and re-create if type is changed\n            that.removeDom(gradient);\n            that.add(gradient);\n        }\n    });\n};\n\n\n/**\n * Update gradient dom\n *\n * @param {Gradient} gradient zr gradient instance\n * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom\n *                            DOM to update\n */\nGradientManager.prototype.updateDom = function (gradient, dom) {\n    if (gradient.type === 'linear') {\n        dom.setAttribute('x1', gradient.x);\n        dom.setAttribute('y1', gradient.y);\n        dom.setAttribute('x2', gradient.x2);\n        dom.setAttribute('y2', gradient.y2);\n    }\n    else if (gradient.type === 'radial') {\n        dom.setAttribute('cx', gradient.x);\n        dom.setAttribute('cy', gradient.y);\n        dom.setAttribute('r', gradient.r);\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return;\n    }\n\n    if (gradient.global) {\n        // x1, x2, y1, y2 in range of 0 to canvas width or height\n        dom.setAttribute('gradientUnits', 'userSpaceOnUse');\n    }\n    else {\n        // x1, x2, y1, y2 in range of 0 to 1\n        dom.setAttribute('gradientUnits', 'objectBoundingBox');\n    }\n\n    // Remove color stops if exists\n    dom.innerHTML = '';\n\n    // Add color stops\n    var colors = gradient.colorStops;\n    for (var i = 0, len = colors.length; i < len; ++i) {\n        var stop = this.createElement('stop');\n        stop.setAttribute('offset', colors[i].offset * 100 + '%');\n\n        var color = colors[i].color;\n        if (color.indexOf('rgba' > -1)) {\n            // Fix Safari bug that stop-color not recognizing alpha #9014\n            var opacity = parse(color)[3];\n            var hex = toHex(color);\n\n            // stop-color cannot be color, since:\n            // The opacity value used for the gradient calculation is the\n            // *product* of the value of stop-opacity and the opacity of the\n            // value of stop-color.\n            // See https://www.w3.org/TR/SVG2/pservers.html#StopOpacityProperty\n            stop.setAttribute('stop-color', '#' + hex);\n            stop.setAttribute('stop-opacity', opacity);\n        }\n        else {\n            stop.setAttribute('stop-color', colors[i].color);\n        }\n\n        dom.appendChild(stop);\n    }\n\n    // Store dom element in gradient, to avoid creating multiple\n    // dom instances for the same gradient element\n    gradient._dom = dom;\n};\n\n/**\n * Mark a single gradient to be used\n *\n * @param {Displayable} displayable displayable element\n */\nGradientManager.prototype.markUsed = function (displayable) {\n    if (displayable.style) {\n        var gradient = displayable.style.fill;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n\n        gradient = displayable.style.stroke;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n    }\n};\n\n/**\n * @file Manages SVG clipPath elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG clipPath elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ClippathManager(zrId, svgRoot) {\n    Definable.call(this, zrId, svgRoot, 'clipPath', '__clippath_in_use__');\n}\n\n\ninherits(ClippathManager, Definable);\n\n\n/**\n * Update clipPath.\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.update = function (displayable) {\n    var svgEl = this.getSvgElement(displayable);\n    if (svgEl) {\n        this.updateDom(svgEl, displayable.__clipPaths, false);\n    }\n\n    var textEl = this.getTextSvgElement(displayable);\n    if (textEl) {\n        // Make another clipPath for text, since it's transform\n        // matrix is not the same with svgElement\n        this.updateDom(textEl, displayable.__clipPaths, true);\n    }\n\n    this.markUsed(displayable);\n};\n\n\n/**\n * Create an SVGElement of displayable and create a <clipPath> of its\n * clipPath\n *\n * @param {Displayable} parentEl  parent element\n * @param {ClipPath[]}  clipPaths clipPaths of parent element\n * @param {boolean}     isText    if parent element is Text\n */\nClippathManager.prototype.updateDom = function (\n    parentEl,\n    clipPaths,\n    isText\n) {\n    if (clipPaths && clipPaths.length > 0) {\n        // Has clipPath, create <clipPath> with the first clipPath\n        var defs = this.getDefs(true);\n        var clipPath = clipPaths[0];\n        var clipPathEl;\n        var id;\n\n        var dom = isText ? '_textDom' : '_dom';\n\n        if (clipPath[dom]) {\n            // Use a dom that is already in <defs>\n            id = clipPath[dom].getAttribute('id');\n            clipPathEl = clipPath[dom];\n\n            // Use a dom that is already in <defs>\n            if (!defs.contains(clipPathEl)) {\n                // This happens when set old clipPath that has\n                // been previously removed\n                defs.appendChild(clipPathEl);\n            }\n        }\n        else {\n            // New <clipPath>\n            id = 'zr' + this._zrId + '-clip-' + this.nextId;\n            ++this.nextId;\n            clipPathEl = this.createElement('clipPath');\n            clipPathEl.setAttribute('id', id);\n            defs.appendChild(clipPathEl);\n\n            clipPath[dom] = clipPathEl;\n        }\n\n        // Build path and add to <clipPath>\n        var svgProxy = this.getSvgProxy(clipPath);\n        if (clipPath.transform\n            && clipPath.parent.invTransform\n            && !isText\n        ) {\n            /**\n             * If a clipPath has a parent with transform, the transform\n             * of parent should not be considered when setting transform\n             * of clipPath. So we need to transform back from parent's\n             * transform, which is done by multiplying parent's inverse\n             * transform.\n             */\n            // Store old transform\n            var transform = Array.prototype.slice.call(\n                clipPath.transform\n            );\n\n            // Transform back from parent, and brush path\n            mul$1(\n                clipPath.transform,\n                clipPath.parent.invTransform,\n                clipPath.transform\n            );\n            svgProxy.brush(clipPath);\n\n            // Set back transform of clipPath\n            clipPath.transform = transform;\n        }\n        else {\n            svgProxy.brush(clipPath);\n        }\n\n        var pathEl = this.getSvgElement(clipPath);\n\n        clipPathEl.innerHTML = '';\n        /**\n         * Use `cloneNode()` here to appendChild to multiple parents,\n         * which may happend when Text and other shapes are using the same\n         * clipPath. Since Text will create an extra clipPath DOM due to\n         * different transform rules.\n         */\n        clipPathEl.appendChild(pathEl.cloneNode());\n\n        parentEl.setAttribute('clip-path', 'url(#' + id + ')');\n\n        if (clipPaths.length > 1) {\n            // Make the other clipPaths recursively\n            this.updateDom(clipPathEl, clipPaths.slice(1), isText);\n        }\n    }\n    else {\n        // No clipPath\n        if (parentEl) {\n            parentEl.setAttribute('clip-path', 'none');\n        }\n    }\n};\n\n/**\n * Mark a single clipPath to be used\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.markUsed = function (displayable) {\n    var that = this;\n    if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {\n        each$1(displayable.__clipPaths, function (clipPath) {\n            if (clipPath._dom) {\n                Definable.prototype.markUsed.call(that, clipPath._dom);\n            }\n            if (clipPath._textDom) {\n                Definable.prototype.markUsed.call(that, clipPath._textDom);\n            }\n        });\n    }\n};\n\n/**\n * @file Manages SVG shadow elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG shadow elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ShadowManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['filter'],\n        '__filter_in_use__',\n        '_shadowDom'\n    );\n}\n\n\ninherits(ShadowManager, Definable);\n\n\n/**\n * Create new shadow DOM for fill or stroke if not exist,\n * but will not update shadow if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && hasShadow(displayable.style)) {\n        var style = displayable.style;\n\n        // Create dom in <defs> if not exists\n        var dom;\n        if (style._shadowDom) {\n            // Gradient exists\n            dom = style._shadowDom;\n\n            var defs = this.getDefs(true);\n            if (!defs.contains(style._shadowDom)) {\n                // _shadowDom is no longer in defs, recreate\n                this.addDom(dom);\n            }\n        }\n        else {\n            // New dom\n            dom = this.add(displayable);\n        }\n\n        this.markUsed(displayable);\n\n        var id = dom.getAttribute('id');\n        svgElement.style.filter = 'url(#' + id + ')';\n    }\n};\n\n\n/**\n * Add a new shadow tag in <defs>\n *\n * @param {Displayable} displayable  zrender displayable element\n * @return {SVGFilterElement} created DOM\n */\nShadowManager.prototype.add = function (displayable) {\n    var dom = this.createElement('filter');\n    var style = displayable.style;\n\n    // Set dom id with shadow id, since each shadow instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    style._shadowDomId = style._shadowDomId || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-shadow-' + style._shadowDomId);\n\n    this.updateDom(displayable, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update shadow.\n *\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.update = function (svgElement, displayable) {\n    var style = displayable.style;\n    if (hasShadow(style)) {\n        var that = this;\n        Definable.prototype.update.call(this, displayable, function (style) {\n            that.updateDom(displayable, style._shadowDom);\n        });\n    }\n    else {\n        // Remove shadow\n        this.remove(svgElement, style);\n    }\n};\n\n\n/**\n * Remove DOM and clear parent filter\n */\nShadowManager.prototype.remove = function (svgElement, style) {\n    if (style._shadowDomId != null) {\n        this.removeDom(style);\n        svgElement.style.filter = '';\n    }\n};\n\n\n/**\n * Update shadow dom\n *\n * @param {Displayable} displayable  zrender displayable element\n * @param {SVGFilterElement} dom DOM to update\n */\nShadowManager.prototype.updateDom = function (displayable, dom) {\n    var domChild = dom.getElementsByTagName('feDropShadow');\n    if (domChild.length === 0) {\n        domChild = this.createElement('feDropShadow');\n    }\n    else {\n        domChild = domChild[0];\n    }\n\n    var style = displayable.style;\n    var scaleX = displayable.scale ? (displayable.scale[0] || 1) : 1;\n    var scaleY = displayable.scale ? (displayable.scale[1] || 1) : 1;\n\n    // TODO: textBoxShadowBlur is not supported yet\n    var offsetX, offsetY, blur, color;\n    if (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY) {\n        offsetX = style.shadowOffsetX || 0;\n        offsetY = style.shadowOffsetY || 0;\n        blur = style.shadowBlur;\n        color = style.shadowColor;\n    }\n    else if (style.textShadowBlur) {\n        offsetX = style.textShadowOffsetX || 0;\n        offsetY = style.textShadowOffsetY || 0;\n        blur = style.textShadowBlur;\n        color = style.textShadowColor;\n    }\n    else {\n        // Remove shadow\n        this.removeDom(dom, style);\n        return;\n    }\n\n    domChild.setAttribute('dx', offsetX / scaleX);\n    domChild.setAttribute('dy', offsetY / scaleY);\n    domChild.setAttribute('flood-color', color);\n\n    // Divide by two here so that it looks the same as in canvas\n    // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur\n    var stdDx = blur / 2 / scaleX;\n    var stdDy = blur / 2 / scaleY;\n    var stdDeviation = stdDx + ' ' + stdDy;\n    domChild.setAttribute('stdDeviation', stdDeviation);\n\n    // Fix filter clipping problem\n    dom.setAttribute('x', '-100%');\n    dom.setAttribute('y', '-100%');\n    dom.setAttribute('width', Math.ceil(blur / 2 * 200) + '%');\n    dom.setAttribute('height', Math.ceil(blur / 2 * 200) + '%');\n\n    dom.appendChild(domChild);\n\n    // Store dom element in shadow, to avoid creating multiple\n    // dom instances for the same shadow element\n    style._shadowDom = dom;\n};\n\n/**\n * Mark a single shadow to be used\n *\n * @param {Displayable} displayable displayable element\n */\nShadowManager.prototype.markUsed = function (displayable) {\n    var style = displayable.style;\n    if (style && style._shadowDom) {\n        Definable.prototype.markUsed.call(this, style._shadowDom);\n    }\n};\n\nfunction hasShadow(style) {\n    // TODO: textBoxShadowBlur is not supported yet\n    return style\n        && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY\n            || style.textShadowBlur || style.textShadowOffsetX\n            || style.textShadowOffsetY);\n}\n\n/**\n * SVG Painter\n * @module zrender/svg/Painter\n */\n\nfunction parseInt10$2(val) {\n    return parseInt(val, 10);\n}\n\nfunction getSvgProxy(el) {\n    if (el instanceof Path) {\n        return svgPath;\n    }\n    else if (el instanceof ZImage) {\n        return svgImage;\n    }\n    else if (el instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n}\n\nfunction checkParentAvailable(parent, child) {\n    return child && parent && child.parentNode !== parent;\n}\n\nfunction insertAfter(parent, child, prevSibling) {\n    if (checkParentAvailable(parent, child) && prevSibling) {\n        var nextSibling = prevSibling.nextSibling;\n        nextSibling ? parent.insertBefore(child, nextSibling)\n            : parent.appendChild(child);\n    }\n}\n\nfunction prepend(parent, child) {\n    if (checkParentAvailable(parent, child)) {\n        var firstChild = parent.firstChild;\n        firstChild ? parent.insertBefore(child, firstChild)\n            : parent.appendChild(child);\n    }\n}\n\nfunction remove$1(parent, child) {\n    if (child && parent && child.parentNode === parent) {\n        parent.removeChild(child);\n    }\n}\n\nfunction getTextSvgElement(displayable) {\n    return displayable.__textSvgEl;\n}\n\nfunction getSvgElement(displayable) {\n    return displayable.__svgEl;\n}\n\n/**\n * @alias module:zrender/svg/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar SVGPainter = function (root, storage, opts, zrId) {\n\n    this.root = root;\n    this.storage = storage;\n    this._opts = opts = extend({}, opts || {});\n\n    var svgRoot = createElement('svg');\n    svgRoot.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n    svgRoot.setAttribute('version', '1.1');\n    svgRoot.setAttribute('baseProfile', 'full');\n    svgRoot.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';\n\n    this.gradientManager = new GradientManager(zrId, svgRoot);\n    this.clipPathManager = new ClippathManager(zrId, svgRoot);\n    this.shadowManager = new ShadowManager(zrId, svgRoot);\n\n    var viewport = document.createElement('div');\n    viewport.style.cssText = 'overflow:hidden;position:relative';\n\n    this._svgRoot = svgRoot;\n    this._viewport = viewport;\n\n    root.appendChild(viewport);\n    viewport.appendChild(svgRoot);\n\n    this.resize(opts.width, opts.height);\n\n    this._visibleList = [];\n};\n\nSVGPainter.prototype = {\n\n    constructor: SVGPainter,\n\n    getType: function () {\n        return 'svg';\n    },\n\n    getViewportRoot: function () {\n        return this._viewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true);\n\n        this._paintList(list);\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        // TODO gradient\n        this._viewport.style.background = backgroundColor;\n    },\n\n    _paintList: function (list) {\n        this.gradientManager.markAllUnused();\n        this.clipPathManager.markAllUnused();\n        this.shadowManager.markAllUnused();\n\n        var svgRoot = this._svgRoot;\n        var visibleList = this._visibleList;\n        var listLen = list.length;\n\n        var newVisibleList = [];\n        var i;\n        for (i = 0; i < listLen; i++) {\n            var displayable = list[i];\n            var svgProxy = getSvgProxy(displayable);\n            var svgElement = getSvgElement(displayable)\n                || getTextSvgElement(displayable);\n            if (!displayable.invisible) {\n                if (displayable.__dirty) {\n                    svgProxy && svgProxy.brush(displayable);\n\n                    // Update clipPath\n                    this.clipPathManager.update(displayable);\n\n                    // Update gradient and shadow\n                    if (displayable.style) {\n                        this.gradientManager\n                            .update(displayable.style.fill);\n                        this.gradientManager\n                            .update(displayable.style.stroke);\n\n                        this.shadowManager\n                            .update(svgElement, displayable);\n                    }\n\n                    displayable.__dirty = false;\n                }\n                newVisibleList.push(displayable);\n            }\n        }\n\n        var diff = arrayDiff$1(visibleList, newVisibleList);\n        var prevSvgElement;\n\n        // First do remove, in case element moved to the head and do remove\n        // after add\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = visibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    remove$1(svgRoot, svgElement);\n                    remove$1(svgRoot, textSvgElement);\n                }\n            }\n        }\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.added) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    prevSvgElement\n                        ? insertAfter(svgRoot, svgElement, prevSvgElement)\n                        : prepend(svgRoot, svgElement);\n                    if (svgElement) {\n                        insertAfter(svgRoot, textSvgElement, svgElement);\n                    }\n                    else if (prevSvgElement) {\n                        insertAfter(\n                            svgRoot, textSvgElement, prevSvgElement\n                        );\n                    }\n                    else {\n                        prepend(svgRoot, textSvgElement);\n                    }\n                    // Insert text\n                    insertAfter(svgRoot, textSvgElement, svgElement);\n                    prevSvgElement = textSvgElement || svgElement\n                        || prevSvgElement;\n\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(prevSvgElement, displayable);\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n            else if (!item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    prevSvgElement =\n                        svgElement =\n                        getTextSvgElement(displayable)\n                        || getSvgElement(displayable)\n                        || prevSvgElement;\n\n                    this.gradientManager.markUsed(displayable);\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.shadowManager.markUsed(displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n        }\n\n        this.gradientManager.removeUnused();\n        this.clipPathManager.removeUnused();\n        this.shadowManager.removeUnused();\n\n        this._visibleList = newVisibleList;\n    },\n\n    _getDefs: function (isForceCreating) {\n        var svgRoot = this._svgRoot;\n        var defs = this._svgRoot.getElementsByTagName('defs');\n        if (defs.length === 0) {\n            // Not exist\n            if (isForceCreating) {\n                var defs = svgRoot.insertBefore(\n                    createElement('defs'), // Create new tag\n                    svgRoot.firstChild // Insert in the front of svg\n                );\n                if (!defs.contains) {\n                    // IE doesn't support contains method\n                    defs.contains = function (el) {\n                        var children = defs.children;\n                        if (!children) {\n                            return false;\n                        }\n                        for (var i = children.length - 1; i >= 0; --i) {\n                            if (children[i] === el) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    };\n                }\n                return defs;\n            }\n            else {\n                return null;\n            }\n        }\n        else {\n            return defs[0];\n        }\n    },\n\n    resize: function (width, height) {\n        var viewport = this._viewport;\n        // FIXME Why ?\n        viewport.style.display = 'none';\n\n        // Save input w/h\n        var opts = this._opts;\n        width != null && (opts.width = width);\n        height != null && (opts.height = height);\n\n        width = this._getSize(0);\n        height = this._getSize(1);\n\n        viewport.style.display = '';\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var viewportStyle = viewport.style;\n            viewportStyle.width = width + 'px';\n            viewportStyle.height = height + 'px';\n\n            var svgRoot = this._svgRoot;\n            // Set width by 'svgRoot.width = width' is invalid\n            svgRoot.setAttribute('width', width);\n            svgRoot.setAttribute('height', height);\n        }\n    },\n\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10$2(stl[wh]) || parseInt10$2(root.style[wh]))\n            - (parseInt10$2(stl[plt]) || 0)\n            - (parseInt10$2(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._svgRoot =\n            this._viewport =\n            this.storage =\n            null;\n    },\n\n    clear: function () {\n        if (this._viewport) {\n            this.root.removeChild(this._viewport);\n        }\n    },\n\n    pathToDataUrl: function () {\n        this.refresh();\n        var html = this._svgRoot.outerHTML;\n        return 'data:image/svg+xml;charset=UTF-8,' + html;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport$1(method) {\n    return function () {\n        zrLog('In SVG mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsuppoted methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer',\n    'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer',\n    'toDataURL', 'pathToImage'\n], function (name) {\n    SVGPainter.prototype[name] = createMethodNotSupport$1(name);\n});\n\nregisterPainter('svg', SVGPainter);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Import all charts and components\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\nexports.zrender = zrender;\nexports.number = number;\nexports.format = format;\nexports.throttle = throttle;\nexports.helper = helper;\nexports.matrix = matrix;\nexports.vector = vector;\nexports.color = color;\nexports.parseGeoJSON = parseGeoJson$1;\nexports.parseGeoJson = parseGeoJson;\nexports.util = ecUtil;\nexports.graphic = graphic$1;\nexports.List = List;\nexports.Model = Model;\nexports.Axis = Axis;\nexports.env = env$1;\n\n})));\n//# sourceMappingURL=echarts.js.map\n"
  },
  {
    "path": "src/main/webapp/static/js/header.js",
    "content": "﻿//验证用户身份\nfunction init_manage(){\n    var user_json = JSON.parse(localStorage.getItem(\"userJson\"));\n    var user_role = user_json.user_role;  //身份验证\n    var nav = $(\".nav\").find(\"ul\");\n    var html;\n    if(user_json.user_role == 1){\n        html = \"<li><a href=\\\"./manage.jsp\\\" onclick=\\\"managePage()\\\">管理</a></li>\"\n        nav.append(html);\n    }\n    function managePage(){\n        localStorage.setItem(\"cardId\",0);\n    }\n}\n\n//验证用户身份\nfunction init_comment(){\n    var user = localStorage.getItem(\"userJson\");\n    var commentListContainer = $(\".comment-list-container\").find(\"ul\");   \n    if(user == null){\n        $.ajax({\n            type:'post',\n            url: url + \"/movie/findMovieById\",\n            dataType:'json',\n            data: {\n                movie_id: movie_id\n            },\n            success:function (obj) {\n                console.log(obj);\n                for(var i=0;i<obj.data.commentList.length;i++){\n                    commentListContainer.append(\n                        \"<li class=\\\"comment-container\\\">\" +\n                            \"<div class=\\\"portrait-container\\\">\" +\n                                \"<div class=\\\"portrait\\\">\" +\n                                    \"<img src=\\\"\"+ obj.data.commentList[i].comment_user.user_headImg +\"\\\" alt=\\\"\\\">\" +\n                                \"</div>\" +\n                                \"<i class=\\\"level-4-icon\\\"></i>\" +\n                            \"</div>\" +\n                            \"<div class=\\\"main2\\\">\" +\n                                \"<div class=\\\"main2-header clearfix\\\">\" +\n                                    \"<div class=\\\"user\\\">\" +\n                                        \"<span class=\\\"name\\\">\" + obj.data.commentList[i].comment_user.user_name + \"</span>\t\" +\n                                        \"<span class=\\\"tag\\\">购</span>\" +\n                                    \"</div>\" +\n                                    \"<div class=\\\"time\\\" title=\\\"2018-11-16 12:06:10\\\">\" +\n                                        \"<span title=\\\"2018-11-16 12:06:10\\\">\" + obj.data.commentList[i].comment_time + \"</span>\" +\n                                    \"</div>\" +\n                                    \"<div class=\\\"approve\\\" data-id=\\\"1044884745\\\">\" +\n                                    \"</div>\" +\n                                \"</div>\" +\n                                \"<div class=\\\"comment-content\\\"> \" +\n                                    obj.data.commentList[i].comment_content +\n                                \"</div>\" +\n                            \"</div>\" +\n                        \"</ul>\"\n                    );\n                }\n            }\n        });\n    }else{\n        user = eval('(' + user + ')');\n        var user_role = user.user_role;  //身份验证\n        var user_name = user.user_name;\n        var html;\n        $.ajax({\n            type:'post',\n            url: url + \"/movie/findMovieById\",\n            dataType:'json',\n            data: {\n                movie_id: movie_id\n            },\n            success:function (obj) {\n                console.log(obj);\n                for(var i=0;i<obj.data.commentList.length;i++){\n                    if((user_role == 1) && (user_name == obj.data.commentList[i].comment_user.user_name)){\n                        html =  \"<div class=\\\"updateBtn\\\" onclick='updateConfirm(\\\"\" + obj.data.commentList[i].comment_id + \"\\\",\\\"\" + obj.data.commentList[i].comment_user.user_name + \"\\\",\\\"\" + obj.data.commentList[i].comment_content + \"\\\",\\\"\" + obj.data.commentList[i].comment_time + \"\\\")'>修改</div>\" +\n                        \"<div class=\\\"deleteCom\\\" onclick='deleteConfirm(\\\"\" + obj.data.commentList[i].comment_id + \"\\\")'>删除</div>\";\n                    }else if(user_role == 1){\n                        html = \"<div class=\\\"deleteCom\\\" onclick='deleteConfirm(\\\"\" + obj.data.commentList[i].comment_id + \"\\\")'>删除</div>\";\n                    }else if((user_name == obj.data.commentList[i].comment_user.user_name) && (user_role != 1)){\n                                html = \"<div class=\\\"updateBtn\\\" onclick='updateConfirm(\\\"\" + obj.data.commentList[i].comment_id + \"\\\",\\\"\" + obj.data.commentList[i].comment_user.user_name + \"\\\",\\\"\" + obj.data.commentList[i].comment_content + \"\\\",\\\"\" + obj.data.commentList[i].comment_time + \"\\\")'>修改</div>\";\n                    }else{\n                        html=\"\";\n                    }   \n                    commentListContainer.append(\n                        \"<li class=\\\"comment-container\\\">\" +\n                            \"<div class=\\\"portrait-container\\\">\" +\n                                \"<div class=\\\"portrait\\\">\" +\n                                    \"<img src=\\\"\"+ obj.data.commentList[i].comment_user.user_headImg +\"\\\" alt=\\\"\\\">\" +\n                                \"</div>\" +\n                                \"<i class=\\\"level-4-icon\\\"></i>\" +\n                            \"</div>\" +\n                            \"<div class=\\\"main2\\\">\" +\n                                \"<div class=\\\"main2-header clearfix\\\">\" +\n                                    \"<div class=\\\"user\\\">\" +\n                                        \"<span class=\\\"name\\\">\" + obj.data.commentList[i].comment_user.user_name + \"</span>\t\" +\n                                        \"<span class=\\\"tag\\\">购</span>\" +\n                                    \"</div>\" +\n                                    \"<div class=\\\"time\\\" title=\\\"2018-11-16 12:06:10\\\">\" +\n                                        \"<span title=\\\"2018-11-16 12:06:10\\\">\" + obj.data.commentList[i].comment_time + \"</span>\" +\n                                    \"</div>\" +\n                                    \"<div class=\\\"approve\\\" data-id=\\\"1044884745\\\">\" +\n                                        html +\n                                    \"</div>\" +\n                                \"</div>\" +\n                                \"<div class=\\\"comment-content\\\"> \" +\n                                    obj.data.commentList[i].comment_content +\n                                \"</div>\" +\n                            \"</div>\" +\n                        \"</ul>\"\n                    );\n                }\n            }\n        });\n    }\n}\n\n//初始化\nfunction initHeader(){\n    var LayuiNavMore = $(\".header-li\");\n    console.log(LayuiNavMore);\n    var user_json = JSON.parse(localStorage.getItem(\"userJson\"));\n    console.log(user_json);\n    layui.use('element', function(){\n        var element = layui.element; //导航的hover效果、二级菜单等功能，需要依赖element模块\n        //监听导航点击\n        element.on('nav(demo)', function(elem){\n            //console.log(elem)\n            layer.msg(elem.text());\n        });\n    });\n    if(user_json == null){\n        LayuiNavMore.append(\n            \"<a href=\\\"javascript:;\\\" style=\\\"padding: 0;height: 42px; width: 42px;\\\"><img src=\\\"../static/images/head.jpg\\\" class=\\\"layui-nav-img\\\"></a>\" +\n            \"<dl class=\\\"layui-nav-child nav-image\\\">\" +\n                \"<dd><a href=\\\"./login.jsp\\\">登录</a></dd>\" +\n            \"</dl>\"\n        );\n    }\n    else{\n        var HeadImg = \"\";\n    \tif(user_json.user_headImg == null || typeof user_json.user_headImg == \"undefined\"){\n            HeadImg = \"../upload/head/demo.jpg\";\n        }else{\n            HeadImg = user_json.user_headImg;\n        }\n        LayuiNavMore.append(\n            \"<a href=\\\"javascript:;\\\" style=\\\"padding: 0;height: 42px; width: 42px;\\\"><img src=\\\"\" + HeadImg + \"\\\" class=\\\"layui-nav-img\\\"></a>\" +\n            \"<dl class=\\\"layui-nav-child nav-image\\\">\" +\n            \"<dd><a href=\\\"./center.jsp\\\" onclick=\\\"mycenter()\\\">我的订单</a></dd>\" +\n            \"<hr/>\" +\n            \"<dd><a href=\\\"./center.jsp\\\" onclick=\\\"myinformation()\\\">基本信息</a></dd>\" +\n                \"<hr/>\" +\n                \"<dd><a onclick=\\\"ReLogin()\\\" style=\\\"text-decoration: none; cursor: pointer;\\\">注销</a></dd>\" +\n                \"<hr/>\" +\n            \"</dl>\"\n        );\n        init_manage();\n    }\n\n}\nfunction mycenter(){\n    localStorage.setItem(\"usercardId\",0);\n}\nfunction myinformation(){\n    localStorage.setItem(\"usercardId\",1);\n}\n//注销\nfunction ReLogin(){\n    layui.use(['layer'], function(){\n    var layer = layui.layer;\n        layer.alert('确认要注销吗？',{icon: 0,offset: clientHeight/5},\n            function (){\n                $.ajax({\n                    type:'post',\n                    url: url + \"/user/logout\",\n                    dataType:'json',\n                    data: {},\n                    success:function (obj) {\n                        localStorage.removeItem('userJson');\n                        layer.closeAll();\n                        window.location.href = \"./mainPage.jsp\";\n                    }\n                });\n            }\n        );\n    });\n}"
  },
  {
    "path": "src/main/webapp/static/js/main2.js",
    "content": "/**\n * main.js\n * http://www.codrops.com\n *\n * Licensed under the MIT license.\n * http://www.opensource.org/licenses/mit-license.php\n * \n * Copyright 2015, Codrops\n * http://www.codrops.com\n */\n;(function(window) {\n\n\t'use strict';\n\n\t/**\n\t * some helper functions\n\t */\n\t\n\t/**********************************************/\n\t/** https://gist.github.com/desandro/1866474 **/\n\t/**********************************************/\n\tvar lastTime = 0;\n\tvar prefixes = 'webkit moz ms o'.split(' ');\n\t// get unprefixed rAF and cAF, if present\n\tvar requestAnimationFrame = window.requestAnimationFrame;\n\tvar cancelAnimationFrame = window.cancelAnimationFrame;\n\t// loop through vendor prefixes and get prefixed rAF and cAF\n\tvar prefix;\n\tfor( var i = 0; i < prefixes.length; i++ ) {\n\t\tif ( requestAnimationFrame && cancelAnimationFrame ) {\n\t\t\tbreak;\n\t\t}\n\t\tprefix = prefixes[i];\n\t\trequestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];\n\t\tcancelAnimationFrame  = cancelAnimationFrame  || window[ prefix + 'CancelAnimationFrame' ] ||\n\t\twindow[ prefix + 'CancelRequestAnimationFrame' ];\n\t}\n\n\t// fallback to setTimeout and clearTimeout if either request/cancel is not supported\n\tif ( !requestAnimationFrame || !cancelAnimationFrame ) {\n\t\trequestAnimationFrame = function( callback, element ) {\n\t\t\tvar currTime = new Date().getTime();\n\t\t\tvar timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );\n\t\t\tvar id = window.setTimeout( function() {\n\t\t\t\tcallback( currTime + timeToCall );\n\t\t\t}, timeToCall );\n\t\t\tlastTime = currTime + timeToCall;\n\t\t\treturn id;\n\t\t};\n\n\t\tcancelAnimationFrame = function( id ) {\n\t\t\twindow.clearTimeout( id );\n\t\t};\n\t}\n\n\tfunction throttle(fn, delay) {\n\t\tvar allowSample = true;\n\n\t\treturn function(e) {\n\t\t\tif (allowSample) {\n\t\t\t\tallowSample = false;\n\t\t\t\tsetTimeout(function() { allowSample = true; }, delay);\n\t\t\t\tfn(e);\n\t\t\t}\n\t\t};\n\t}\n\n\t// from http://www.quirksmode.org/js/events_properties.html#position\n\tfunction getMousePos(e) {\n\t\tvar posx = 0;\n\t\tvar posy = 0;\n\t\tif (!e) var e = window.event;\n\t\tif (e.pageX || e.pageY) \t{\n\t\t\tposx = e.pageX;\n\t\t\tposy = e.pageY;\n\t\t}\n\t\telse if (e.clientX || e.clientY) \t{\n\t\t\tposx = e.clientX + document.body.scrollLeft\n\t\t\t\t+ document.documentElement.scrollLeft;\n\t\t\tposy = e.clientY + document.body.scrollTop\n\t\t\t\t+ document.documentElement.scrollTop;\n\t\t}\n\t\treturn {\n\t\t\tx : posx,\n\t\t\ty : posy\n\t\t}\n\t}\n\n\t// equation of a line\n\tfunction lineEq(y2, y1, x2, x1, currentVal) {\n\t\t// y = mx + b\n\t\tvar m = (y2 - y1) / (x2 - x1),\n\t\t\tb = y1 - m * x1;\n\n\t\treturn m * currentVal + b;\n\t}\n\n\tvar support = {transitions : Modernizr.csstransitions},\n\t\ttransEndEventNames = {'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend'},\n\t\ttransEndEventName = transEndEventNames[Modernizr.prefixed('transition')],\n\t\tonEndTransition = function(el, callback) {\n\t\t\tvar onEndCallbackFn = function( ev ) {\n\t\t\t\tif( support.transitions ) {\n\t\t\t\t\tif( ev.target != this ) return;\n\t\t\t\t\tthis.removeEventListener( transEndEventName, onEndCallbackFn );\n\t\t\t\t}\n\t\t\t\tif( callback && typeof callback === 'function' ) { callback.call(this); }\n\t\t\t};\n\t\t\tif( support.transitions ) {\n\t\t\t\tel.addEventListener( transEndEventName, onEndCallbackFn );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tonEndCallbackFn();\n\t\t\t}\n\t\t},\n\t\t// main container\n\t\tcontainer = document.querySelector('.container'),\n\t\t// the 3D element - the room\n\t\troom = container.querySelector('.cube'),\n\t\t// the seat rows inside the 3D element\n\t\trows = [].slice.call(room.querySelectorAll('.rows > .row')),\n\t\t// total amount of rows\n\t\ttotalRows = rows.length,\n\t\t// seats\n\t\tseats = [].slice.call(room.querySelectorAll('.row__seat')),\n\t\t// the plan/map\n\t\tplan = document.querySelector('.plan'),\n\t\t// seats on the plan/map\n\t\tplanseats = [].slice.call(plan.querySelectorAll('.row__seat')),\n\t\t// the screen\n\t\tmonitor = room.querySelector('.screen'),\n\t\t// the video element\n\t\tvideo = monitor.querySelector('video'),\n\t\t// play video control\n\t\tplayCtrl = monitor.querySelector('button.action--play'),\n\t\t// intro element\n\t\tintro = monitor.querySelector('.intro'),\n\t\t// 'select your seats' control\n\t\tselectSeatsCtrl = intro.querySelector('button.action--seats'),\n\t\t// the tilt control\n\t\ttiltCtrl = document.querySelector('.action--lookaround'),\n\t\t// how much the camera rotates when the user moves the mouse\n\t\ttiltRotation = {\n\t\t\trotateX : 25, // a relative rotation of -25deg to 25deg on the x-axis\n\t\t\trotateY : 15  // a relative rotation of -15deg to 15deg on the y-axis\n\t\t},\n\t\t// controls whether the tilt is active or not\n\t\ttilt = false,\n\t\t// window sizes\n\t\twinsize = {width: window.innerWidth, height: window.innerHeight},\n\t\t// width of one seat\n\t\tseat_width = seats[0].offsetWidth,\n\t\t// number of seats per row\n\t\tseats_row = rows[0].children.length,\n\t\t// the sum of the room´s left margin with the room´s right margin is four times the width of a seat \n\t\tside_margin = 4 * seat_width,\n\t\t\n\t\t// if the following is changed, the CSS values also need to be adjusted (and vice-versa)\n\t\t// distance from first row to the screen\n\t\trow_front_gap = 800,\n\t\t// distance between rows\n\t\trow_back = 100,\n\t\t// the gap of seats in the middle of the room (equivalent to two columns of seats)\n\t\trow_gap_amount = 2,\n\t\t// perspective value\n\t\tperspective = 2000,\n\t\t// transition settings for the room animations (moving camera to seat)\n\t\ttransitionOpts = {'speed' : 1000, 'easing' : 'cubic-bezier(.7,0,.3,1)'},\n\n\t\t// the room dimentions\n\t\troomsize = {\n\t\t\tx : seats_row * seat_width + side_margin + row_gap_amount * seat_width,\n\t\t\ty : 1000, // SCSS $cube_y\n\t\t\tz : 3000 // SCSS $cube_z\n\t\t},\n\t\t// the initial values for the room transform\n\t\tinitTransform = {\n\t\t\ttranslateX : 0,\n\t\t\ttranslateY : roomsize.y/3.5, // view from top..\n\t\t\ttranslateZ : 0,\n\t\t\trotateX : -15, // ..looking down\n\t\t\trotateY : 0\n\t\t},\n\t\t// the current room transform\n\t\troomTransform = initTransform;\n\n\tfunction init() {\n\t\t// scale room to fit viewport\n\t\tscaleRoom();\n\t\t// initial view (zoomed screen)\n\t\tapplyRoomTransform({'translateX' : 0, 'translateY' : 0, 'translateZ' : 1300, 'rotateX' : 0, 'rotateY' : 0});\n\t\t// bind events\n\t\tinitEvents();\n\t}\n\n\tfunction applyRoomTransform(transform) {\n\t\troom.style.WebkitTransform = room.style.transform = transform ? 'translate3d(0,0,' + perspective + 'px) rotate3d(1,0,0,' + transform.rotateX + 'deg) rotate3d(0,1,0,' + transform.rotateY + 'deg) translate3d(' + transform.translateX + 'px, ' + transform.translateY + 'px, ' + transform.translateZ + 'px)'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  : 'translate3d(0,0,' + perspective + 'px) rotate3d(1,0,0,' + roomTransform.rotateX + 'deg) rotate3d(0,1,0,' + roomTransform.rotateY + 'deg) translate3d(' + roomTransform.translateX + 'px, ' + roomTransform.translateY + 'px, ' + roomTransform.translateZ + 'px)';\n\t}\n\n\tfunction applyRoomTransition(settings) {\n\t\tvar settings = settings || transitionOpts;\n\t\troom.style.WebkitTransition = '-webkit-transform ' + settings.speed + 'ms ' + settings.easing;\n\t\troom.style.transition = 'transform ' + settings.speed + 'ms ' + settings.easing;\n\t}\n\n\tfunction removeRoomTransition() {\n\t\troom.style.WebkitTransition = room.style.transition = 'none';\n\t}\n\n\tfunction scaleRoom() {\n\t\tvar factor = winsize.width / roomsize.x;\n\t\tcontainer.style.WebkitTransform = container.style.transform = 'scale3d(' + factor + ',' + factor + ',1)';\n\t}\n\n\tfunction initEvents() {\n\t\t// select a seat\n\t\tvar onSeatSelect = function(ev) { selectSeat(ev.target); };\n\t\tplanseats.forEach(function(planseat) {\n\t\t\tplanseat.addEventListener('click', onSeatSelect);\n\t\t});\n\n\t\t// enabling/disabling the tilt\n\t\tvar onTiltCtrlClick = function() {\n\t\t\t// if tilt is enabled..\n\t\t\tif( tilt ) {\n\t\t\t\tdisableTilt();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tenableTilt();\n\t\t\t}\n\t\t};\n\t\ttiltCtrl.addEventListener('click', onTiltCtrlClick);\n\n\t\t// mousemove event / tilt functionality\n\t\tvar onMouseMove = function(ev) {\n\t\t\trequestAnimationFrame(function() {\n\t\t\t\tif( !tilt ) return false;\n\n\t\t\t\tvar mousepos = getMousePos(ev),\n\t\t\t\t\t// transform values\n\t\t\t\t\trotX = tiltRotation.rotateX ? roomTransform.rotateX -  (2 * tiltRotation.rotateX / winsize.height * mousepos.y - tiltRotation.rotateX) : 0,\n\t\t\t\t\trotY = tiltRotation.rotateY ? roomTransform.rotateY +  (2 * tiltRotation.rotateY / winsize.width * mousepos.x - tiltRotation.rotateY) : 0;\n\t\t\n\t\t\t\t// apply transform\n\t\t\t\tapplyRoomTransform({'translateX' : roomTransform.translateX, 'translateY' : roomTransform.translateY, 'translateZ' : roomTransform.translateZ, 'rotateX' : rotX, 'rotateY' : rotY});\n\t\t\t});\n\t\t};\n\t\tdocument.addEventListener('mousemove', onMouseMove);\n\n\t\t// select seats control click (intro button): show the room layout\n\t\tvar onSelectSeats = function() { \n\t\t\tclassie.remove(intro, 'intro--shown');\n\t\t\tclassie.add(plan, 'plan--shown');\n\t\t\tclassie.add(playCtrl, 'action--faded');\n\t\t\tzoomOutScreen(function() {\n\t\t\t\tshowTiltCtrl();\n\t\t\t}); \n\t\t};\n\t\tselectSeatsCtrl.addEventListener('click', onSelectSeats);\n\n\t\t// play video\n\t\tplayCtrl.addEventListener('click', videoPlay);\n\t\t// ended video event\n\t\tvideo.addEventListener('ended', videoLoad);\n\n\t\t// window resize: update window size\n\t\twindow.addEventListener('resize', throttle(function(ev) {\n\t\t\twinsize = {width: window.innerWidth, height: window.innerHeight};\n\t\t\tscaleRoom();\n\t\t}, 10));\n\t}\n\n\tfunction showTiltCtrl() {\n\t\tclassie.add(tiltCtrl, 'action--shown');\n\t}\n\n\t// select a seat on the seat plan\n\tfunction selectSeat(planseat) {\n\t\tif( classie.has(planseat, 'row__seat--reserved') ) {\n\t\t\treturn false;\n\t\t}\n\t\tif( classie.has(planseat, 'row__seat--selected') ) {\n\t\t\tclassie.remove(planseat, 'row__seat--selected');\n\t\t\treturn false;\n\t\t}\n\t\t// add selected class\n\t\tclassie.add(planseat, 'row__seat--selected');\n\n\t\t// the real seat\n\t\tvar seat = seats[planseats.indexOf(planseat)];\n\t\t// show the seat´s perspective\n\t\tpreviewSeat(seat);\n\t}\n\n\t// preview perspective from the selected seat. Moves the camera to that position.\n\tfunction previewSeat(seat) {\n\t\t// disable tilt\n\t\tdisableTilt();\n\t\t// change transition properties\n\t\tapplyRoomTransition();\n\t\t// getComputedStyle: https://css-tricks.com/get-value-of-css-rotation-through-javascript/\n\t\tvar st = window.getComputedStyle(seat.parentNode, null),\n\t\t\ttr = st.getPropertyValue('-webkit-transform') ||\n\t\t\t\t st.getPropertyValue('-moz-transform') ||\n\t\t\t\t st.getPropertyValue('-ms-transform') ||\n\t\t\t\t st.getPropertyValue('-o-transform') ||\n\t\t\t\t st.getPropertyValue('transform') ||\n\t\t\t\t 'Either no transform set, or browser doesn´t do getComputedStyle';\n\t\t\t\n\t\tif( tr === 'none' ) return;\n\t\t\n\t\tvar values = tr.split('(')[1],\n\t\t\tvalues = values.split(')')[0],\n\t\t\tvalues = values.split(','),\n\t\t\t\n\t\t\t// translateY value of this seat´s row\n\t\t\ty = values[13],\n\t\t\t// translateZ value of this seat´s row\n\t\t\tz = values[14],\n\t\t\n\t\t\t// seat´s center point (x-axis)\n\t\t\tseatCenterX = seat.offsetLeft + side_margin/2 + seat.offsetWidth/2,\n\n\t\t\t// translateX, translateY and translateZ values\n\t\t\ttx = seatCenterX < roomsize.x/2 ? initTransform.translateX + (roomsize.x/2 - seatCenterX) : initTransform.translateX - (seatCenterX - roomsize.x/2),\n\t\t\tty = roomsize.y/2 - (roomsize.y - Math.abs(y)) + seat.offsetHeight + 10, // add a small extra\n\t\t\ttz = Math.abs(z)+10, // add a small extra\n\n\t\t\t// calculate how much to rotate in the x-axis (the more close to the screen the more we need to rotate)\n\t\t\tfirstRowZ = roomsize.z - row_front_gap,\n\t\t\tlastRowZ = firstRowZ - (totalRows - 1 + row_gap_amount) * row_back,\n\t\t\t\n\t\t\t// calculate how much to rotate in the y-axis (the more close to the screen the more we need to rotate.\n\t\t\t// Also the same applies when the distance from the center of the room to both sides increases.\n\t\t\t// for the last row:\n\t\t\tminRotY_1 = 0, maxRotY_1 = 20, // min and max values for y rotation\n\t\t\tinitialTranslationX = 0, finalTranslationX = roomsize.x/2,\n\t\t\trotY_1 = lineEq(minRotY_1, maxRotY_1, initialTranslationX, finalTranslationX, tx),\n\t\t\t// for the first row:\n\t\t\tminRotY_2 = 0, maxRotY_2 = 50, // min and max values for y rotation\n\t\t\trotY_2 = lineEq(minRotY_2, maxRotY_2, initialTranslationX, finalTranslationX, tx),\n\t\t\t// final:\n\t\t\trotY = lineEq(rotY_1, rotY_2, lastRowZ, firstRowZ, Math.abs(z));\n\n\t\t// room transforms\n\t\troomTransform = {\n\t\t\ttranslateX : tx,\n\t\t\ttranslateY : ty,\n\t\t\ttranslateZ : tz,\n\t\t\trotateX : 0,//rotX,\n\t\t\trotateY : rotY\n\t\t};\n\n\t\t// apply transform\n\t\tapplyRoomTransform();\n\t\t\n\t\tonEndTransition(room, function() {\n\t\t\tremoveRoomTransition();\n\t\t});\n\t}\n\n\tfunction zoomOutScreen(callback) {\n\t\tapplyRoomTransition({'speed' : 1500, 'easing' : 'ease'});\n\t\tapplyRoomTransform(initTransform);\n\t\tonEndTransition(room, function() {\n\t\t\tremoveRoomTransition();\n\t\t\tcallback.call();\n\t\t});\n\t}\n\n\tfunction disableTilt() {\n\t\tclassie.add(tiltCtrl, 'action--disabled');\n\t\ttilt = false;\n\t}\n\n\tfunction enableTilt() {\n\t\tclassie.remove(tiltCtrl, 'action--disabled');\n\t\ttilt = true;\n\t}\n\n\tfunction videoPlay() {\n\t\t// hide the play control\n\t\tclassie.remove(playCtrl, 'action--shown');\n\t\tvideo.currentTime = 0;\n\t\tvideo.play();\n\t}\n\n\tfunction videoLoad() {\n\t\t// show the play control\n\t\tclassie.add(playCtrl, 'action--shown');\n\t\tvideo.load();\n\t}\n\n\tinit();\n\n})(window);"
  },
  {
    "path": "src/main/webapp/static/js/modernizr-custom.js",
    "content": "/*! modernizr 3.2.0 (Custom Build) | MIT *\n * http://modernizr.com/download/?-csstransitions-preserve3d-prefixed-setclasses !*/\n!function(e,n,t){function r(e,n){return typeof e===n}function o(){var e,n,t,o,s,i,a;for(var f in C)if(C.hasOwnProperty(f)){if(e=[],n=C[f],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t<n.options.aliases.length;t++)e.push(n.options.aliases[t].toLowerCase());for(o=r(n.fn,\"function\")?n.fn():n.fn,s=0;s<e.length;s++)i=e[s],a=i.split(\".\"),1===a.length?Modernizr[a[0]]=o:(!Modernizr[a[0]]||Modernizr[a[0]]instanceof Boolean||(Modernizr[a[0]]=new Boolean(Modernizr[a[0]])),Modernizr[a[0]][a[1]]=o),g.push((o?\"\":\"no-\")+a.join(\"-\"))}}function s(e){var n=w.className,t=Modernizr._config.classPrefix||\"\";if(x&&(n=n.baseVal),Modernizr._config.enableJSClass){var r=new RegExp(\"(^|\\\\s)\"+t+\"no-js(\\\\s|$)\");n=n.replace(r,\"$1\"+t+\"js$2\")}Modernizr._config.enableClasses&&(n+=\" \"+t+e.join(\" \"+t),x?w.className.baseVal=n:w.className=n)}function i(e){return e.replace(/([a-z])-([a-z])/g,function(e,n,t){return n+t.toUpperCase()}).replace(/^-/,\"\")}function a(e,n){return!!~(\"\"+e).indexOf(n)}function f(){return\"function\"!=typeof n.createElement?n.createElement(arguments[0]):x?n.createElementNS.call(n,\"http://www.w3.org/2000/svg\",arguments[0]):n.createElement.apply(n,arguments)}function l(e,n){return function(){return e.apply(n,arguments)}}function u(e,n,t){var o;for(var s in e)if(e[s]in n)return t===!1?e[s]:(o=n[e[s]],r(o,\"function\")?l(o,t||n):o);return!1}function p(e){return e.replace(/([A-Z])/g,function(e,n){return\"-\"+n.toLowerCase()}).replace(/^ms-/,\"-ms-\")}function d(){var e=n.body;return e||(e=f(x?\"svg\":\"body\"),e.fake=!0),e}function c(e,t,r,o){var s,i,a,l,u=\"modernizr\",p=f(\"div\"),c=d();if(parseInt(r,10))for(;r--;)a=f(\"div\"),a.id=o?o[r]:u+(r+1),p.appendChild(a);return s=f(\"style\"),s.type=\"text/css\",s.id=\"s\"+u,(c.fake?c:p).appendChild(s),c.appendChild(p),s.styleSheet?s.styleSheet.cssText=e:s.appendChild(n.createTextNode(e)),p.id=u,c.fake&&(c.style.background=\"\",c.style.overflow=\"hidden\",l=w.style.overflow,w.style.overflow=\"hidden\",w.appendChild(c)),i=t(p,e),c.fake?(c.parentNode.removeChild(c),w.style.overflow=l,w.offsetHeight):p.parentNode.removeChild(p),!!i}function m(n,r){var o=n.length;if(\"CSS\"in e&&\"supports\"in e.CSS){for(;o--;)if(e.CSS.supports(p(n[o]),r))return!0;return!1}if(\"CSSSupportsRule\"in e){for(var s=[];o--;)s.push(\"(\"+p(n[o])+\":\"+r+\")\");return s=s.join(\" or \"),c(\"@supports (\"+s+\") { #modernizr { position: absolute; } }\",function(e){return\"absolute\"==getComputedStyle(e,null).position})}return t}function v(e,n,o,s){function l(){p&&(delete N.style,delete N.modElem)}if(s=r(s,\"undefined\")?!1:s,!r(o,\"undefined\")){var u=m(e,o);if(!r(u,\"undefined\"))return u}for(var p,d,c,v,h,y=[\"modernizr\",\"tspan\"];!N.style;)p=!0,N.modElem=f(y.shift()),N.style=N.modElem.style;for(c=e.length,d=0;c>d;d++)if(v=e[d],h=N.style[v],a(v,\"-\")&&(v=i(v)),N.style[v]!==t){if(s||r(o,\"undefined\"))return l(),\"pfx\"==n?v:!0;try{N.style[v]=o}catch(g){}if(N.style[v]!=h)return l(),\"pfx\"==n?v:!0}return l(),!1}function h(e,n,t,o,s){var i=e.charAt(0).toUpperCase()+e.slice(1),a=(e+\" \"+b.join(i+\" \")+i).split(\" \");return r(n,\"string\")||r(n,\"undefined\")?v(a,n,o,s):(a=(e+\" \"+P.join(i+\" \")+i).split(\" \"),u(a,n,t))}function y(e,n,r){return h(e,t,t,n,r)}var g=[],C=[],_={_version:\"3.2.0\",_config:{classPrefix:\"\",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){C.push({name:e,fn:n,options:t})},addAsyncTest:function(e){C.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=_,Modernizr=new Modernizr;var w=n.documentElement,x=\"svg\"===w.nodeName.toLowerCase(),S=\"Moz O ms Webkit\",b=_._config.usePrefixes?S.split(\" \"):[];_._cssomPrefixes=b;var E=function(n){var r,o=prefixes.length,s=e.CSSRule;if(\"undefined\"==typeof s)return t;if(!n)return!1;if(n=n.replace(/^@/,\"\"),r=n.replace(/-/g,\"_\").toUpperCase()+\"_RULE\",r in s)return\"@\"+n;for(var i=0;o>i;i++){var a=prefixes[i],f=a.toUpperCase()+\"_\"+r;if(f in s)return\"@-\"+a.toLowerCase()+\"-\"+n}return!1};_.atRule=E;var P=_._config.usePrefixes?S.toLowerCase().split(\" \"):[];_._domPrefixes=P;var z={elem:f(\"modernizr\")};Modernizr._q.push(function(){delete z.elem});var N={style:z.elem.style};Modernizr._q.unshift(function(){delete N.style}),_.testAllProps=h;_.prefixed=function(e,n,t){return 0===e.indexOf(\"@\")?E(e):(-1!=e.indexOf(\"-\")&&(e=i(e)),n?h(e,n,t):h(e,\"pfx\"))};_.testAllProps=y,Modernizr.addTest(\"csstransitions\",y(\"transition\",\"all\",!0)),Modernizr.addTest(\"preserve3d\",y(\"transformStyle\",\"preserve-3d\")),o(),s(g),delete _.addTest,delete _.addAsyncTest;for(var T=0;T<Modernizr._q.length;T++)Modernizr._q[T]();e.Modernizr=Modernizr}(window,document);"
  },
  {
    "path": "src/main/webapp/static/layui/css/index.css",
    "content": "/**\n \n @Name: layuiNetCompany - 大气风格的网络公司企业模版\n @Author: xuxingyu\n @Copyright: layui.com\n \n */\n\n\nbody{background: #fff;}\n\n/** 首页 */\n\n/*导航部分*/\n.nav{width: 100%; height: 80px; box-shadow: 0 3px 3px 0 #CCC; background: #FFF; position: fixed; left: 0; top: 0; z-index: 999; overflow: hidden; transition: 0.3s}\n.nav.index{background: rgba(255, 255, 255 ,0.8); box-shadow: 0 0 0 0 rgba(0,0,0,0.05);}\n.nav.scroll{ background: #FFF; box-shadow: 0 3px 3px 0 rgba(0,0,0,0.05); transition: 0.3s}\n.nav .layui-container{position: relative; transition: all 400ms ease-out;}\n.nav .nav-logo{height: 100%; position: absolute; top: 0; left: 15px; line-height: 80px;}\n.nav .nav-list{display: inline-block; height: 80px;}\n.nav .nav-list button{width: 25px; height: 30px; position: absolute; top: 30px; right: 15px; background-color: transparent; border: none; outline: none; cursor: pointer;}\n.nav .nav-list button span{display: block; width: 25px; height: 2px; background: #2db5a3; margin-bottom: 6px; transition: 0.5s;}\n.nav .nav-list button span.spa1{transform: rotate(45deg);}\n.nav .nav-list button span.spa3{transform: rotate(-45deg) translate(5px,-5px);}\n.nav .layui-nav{width: 100%; position: absolute; top: 80px; right: 0; color: #000; background: transparent;}\n.nav .layui-nav .layui-nav-item{display: block; line-height: 60px;}\n.nav .layui-nav *{font-size: 18px;}\n.nav .layui-nav .layui-nav-item a{padding: 0 0; color: #000;}\n.nav .layui-nav-bar,\n.nav .layui-nav .layui-this:after{height: 2px; background-color: #2db5a3;}\n.nav .layui-nav .layui-this a\n,.nav .layui-nav .layui-nav-item a:hover{color: #2db5a3;}\n\n/*轮播*/\n#banner img{min-width: 100%; height: 898px;}\n#banner .panel{width: 400px; position: absolute; top: 25%; left: 50%; margin-left: -200px; text-align: center;}\n#banner .panel p{color: #8c8c8c; font-size: 44px; line-height: 80px; letter-spacing: 15px;}\n#banner .panel p.title{color: #4a4a4a; font-size: 54px; letter-spacing: 10px;}\n\n/*主体—产品*/\n.main-product{padding-top: 90px; padding-bottom: 130px;}\n.main-product p{font-size: 16px; color: #ababab; line-height: 28px;}\n.main-product p.title\n,.main-service p.title{color: #484848; font-size: 24px; text-align: center; line-height: 160px;}\n.main-product p.title span\n,.main-service p.title span{color: #2db5a3;}\n.main-product .content{border: 1px solid #DEDEDE; padding: 30px 36px 0 36px; text-align: center; transition: 0.3s;}\n.main-product .content p.label{font-size: 18px; color: #939393; line-height: 46px; padding-top: 6px;}\n.main-product .content a{font-size: 18px; color: #a1d8cb; line-height: 68px;}\n.main-product .content:hover{box-shadow: 0 0 3px 3px #EEE; transition: 0.3s;}\n.main-product .content img{transition: 2s;}\n.main-product .content img:hover{transform: rotateY(180deg);}\n\n/*主体-服务*/\n.main-service{background: #f8f8f8;}\n.main-service .content{position: relative;}\n.main-service .content .content-left{width: 50%;}\n.main-service .content .content-left img{width: 100%;}\n.main-service .content .content-right{box-sizing: border-box; background: #FFF; padding: 58px 40px 0 48px; width: 50%; height: 100%; position: absolute; top: 0; right: 0; transition: 0.3s; overflow: hidden;}\n.main-service .content .content-right p{color: #adadad; line-height: 32px; overflow: hidden; text-overflow: ellipsis;}\n.main-service .content .content-right p.label{font-size: 16px; color: #4a4a4a;}\n.main-service .content .content-right span{display: block; width: 50px; height: 2px; background: #2cb6a1; margin-bottom: 23px;} \n.main-service .content .content-right:hover{box-shadow: 2px 2px 2px #EEE; transition: 0.3s;}\n.main-service .service-more{padding-top: 80px; padding-bottom: 80px; text-align: center;}\n.main-service .service-more a{padding: 10px 62px; font-size: 23px; line-height: 46px;color: #FFF; background: #7fd3c6; border-radius: 3px;}\n\n/*底部*/\n.footer{padding-bottom: 70px; background: #5e6664;}\n.footer .footer-web{padding-top: 50px; padding-bottom: 63px;}\n.footer .footer-web a{color: #a5aaa9; line-height: 22px; margin-right: 20px; transition: 0.3s;}\n.footer .footer-web a:hover{color: #dce1e0; transition: 0.3s;}\n.footer .footer-contact{color: #fff;}\n.footer .footer-contact a{color: #a5aaa9;}\n.footer .footer-contact .contact-top{padding-top: 20px; line-height: 30px;}\n.footer .footer-contact .contact-bottom{line-height: 35px;}\n\n\n/** 产品 */\n.banner{height: 320px; margin-top: 80px;}\n.banner.product{background: url(../img/nav_img1.jpg) no-repeat center top; background-size: cover;}\n.main.product{padding: 30px 0 75px 0;}\n.main.product .content{padding: 50px 0; border-bottom: 1px solid #e8e8e8;}\n.main.product .content .content-img{text-align: center;}\n.main.product .content .content-img img{max-width: 100%;}\n.main.product .content .label{color: #565656; font-size: 30px; line-height: 78px; margin-top: 32px;}\n.main.product .content .detail{font-size: 16px; line-height: 28px; color: #d7d7d7; padding-bottom: 30px;}\n.main.product .content a{color: #a0d2cc; font-size: 16px; line-height: 38px; padding:10px 11px 10px 23px; border: 1px solid #a0d2cc; border-radius: 3px;}\n\n\n/** 动态 */\n.banner.news{background: url(../img/nav_img3.jpg) no-repeat center top; background-size: cover;}\n.banner .title{padding-top: 170px;}\n.banner .title.active{padding-top: 120px; transition: 1.5s;}\n.banner .title p{color: #606060; font-size: 36px; text-align: center; line-height: 50px; letter-spacing: 5px;}\n.banner .title p.en{font-size: 20px; letter-spacing: 3px;}\n.main-news{padding: 70px 0 80px 0;}\n.main-news .content > div{padding-bottom: 40px; border-bottom: 1px dashed #eaeaea; position: relative;}\n.main-news .content .news-img{display: inline-block; width: 30%; vertical-align: top;}\n.main-news .content .news-img img{max-width: 90%;}\n.main-news .content .news-panel{display: inline-block; width: 70%; vertical-align: top; padding-left: 5px; box-sizing: border-box;}\n.main-news .content .news-panel strong a{display: block; color: #555; font-size: 18px; line-height: 26px; overflow: hidden; text-overflow:ellipsis; white-space: nowrap;}\n.main-news .content .news-panel p.detail{color: #777; line-height: 24px;}\n.main-news .content .news-panel p.read-push{color: #AAA; padding-top: 5px;}\n.main-news #newsPage .layui-laypage{display: block; text-align: center; margin-top: 70px;}\n.main-news #newsPage .layui-laypage a,.main-news #newsPage .layui-laypage span{font-size: 18px; line-height: 40px; height: 40px; margin-right: 20px; border-radius: 3px; color: #e3e3e3;}\n/*动态详情页*/\n.main-newsdate{margin-top: 80px; text-align: center;}\n.main-newsdate .news{text-align: left; line-height: 104px;}\n.main-newsdate h1{padding-top: 6px;}\n.main-newsdate .pushtime{color: #686868; font-size: 18px; line-height: 82px;}\n.main-newsdate .introTop{padding-bottom: 28px; font-size: 18px; line-height: 20px; text-align: left;}\n.main-newsdate .introBott{font-size: 18px; line-height: 42px; text-align: justify; padding: 40px 0 102px 0;}\n.main-newsdate img{max-width: 100%;}\n\n\n/** 案例 */\n.banner.case{background: url(../img/nav_img2.jpg) no-repeat center top; background-size: cover;}\n.main-case{padding: 30px 0 75px;}\n.main-case .content{width: 48%; text-align: center; padding-top: 120px; padding-bottom: 20px; border-bottom: 2px solid #c9c9c9;}\n.main-case .content.even{margin-left: 2%;}\n.main-case .content .case-img{border: 1px solid #e2e2e2; overflow: hidden;}\n.main-case .content .case-img img{width: 100%; transition: 2s;}\n.main-case .content .case-img img:hover{transform: scale(1.2,1.2); transition: 2s;}\n.main-case .content p.lable{padding-top: 13px; font-size: 30px; line-height: 76px;}\n.main-case .content p{font-size: 18px; line-height: 32px; color: #505050;}\n.main-case #casePage .layui-laypage{display: block; text-align: center; margin-top: 100px;}\n.main-case #casePage .layui-laypage a,.main-case #casePage .layui-laypage span{font-size: 18px; line-height: 40px; height: 40px; margin-right: 20px; border-radius: 3px; color: #e3e3e3;}\n\n\n/** 关于 */\n.banner.about{background: url(../img/nav_img4.jpg) no-repeat center top; background-size: cover;}\n.main-about{padding-bottom: 130px;}\n.main-about ul.aboutab{padding: 100px 0; text-align: center;}\n.main-about ul.aboutab li{display: inline-block; padding: 0 22px; margin-left: 15px; font-size: 20px; line-height: 46px; color: #b5b5b5; border: 1px solid #e2e2e2; border-radius: 3px; cursor: pointer;}\n.main-about ul.aboutab li:first-child{margin-left: 0;}\n.main-about ul.aboutab li.layui-this\n,.main-about ul.aboutab li:hover{color: #2ab5a3; border-color: #afddd7; transition: 0.3s;}\n.main-about .tabJob, .main-about .tabCour{display: none;}\n/*公司简介*/\n.main-about .tabIntro{padding-bottom: 15px;}\n.main-about .tabIntro .content{vertical-align: middle;}\n.main-about .tabIntro .content .img{width: 50%;}\n.main-about .tabIntro .content .img img{width: 100%;}\n.main-about .tabIntro .content .panel{width: 50%;}\n.main-about .tabIntro .content p{padding: 0 20px; line-height: 24px; text-align: justify;}\n.main-about .tabIntro .p_hidden{padding: 0 20px; display: none;}\n/*招贤纳士*/\n.main-about .tabJob .content{padding: 0 0 40px 20px; border: 1px solid #e2e2e2; border-top: 4px solid #65d0c5; margin-top: 90px;}\n.main-about .tabJob .content:first-child{margin-top: 10px;}\n.main-about .tabJob .content p{font-size: 18px; line-height: 40px;}\n.main-about .tabJob .content p.title{font-size: 24px; color: #545454; line-height: 60px;}\n.main-about .tabJob .content ol{padding-left: 20px; list-style-type: none; counter-reset: sectioncounter;}\n.main-about .tabJob .content ol li{color: #8d8d8d; font-size: 16px; line-height: 30px;}\n.main-about .tabJob .content ol li:before {content: counter(sectioncounter) \"、\"; counter-increment: sectioncounter;}\n/*发展历程*/\n.main-about .tabCour p.title{font-size: 28px; line-height: 28px; text-align: center;}\n.main-about .tabCour .timeline{position: relative; margin-top: 75px;}\n.main-about .tabCour .timeline:before{position: absolute; top: 0; bottom: 0; content: \"\"; width: 2px; background-color: #e2e2e2; left: 50px;}\n.main-about .tabCour .timeline li{position: relative; padding-top: 70px;}\n.main-about .tabCour .timeline li:first-child{padding-top: 0;}\n.main-about .tabCour .timeline li .cour-img{position: absolute; left: 0; width: 100px; border-radius: 50%;}\n.main-about .tabCour .timeline li .cour-img img{width: 100%;}\n.main-about .tabCour .timeline li .cour-panel{padding-top: 20px; padding-left: 120px; text-align: left;}\n.main-about .tabCour .timeline li .cour-panel p.label{font-size: 18px; color: #000;}\n.main-about .tabCour .timeline li .cour-panel p{color: #949494; line-height: 30px;}\n\n\n@media screen and (max-width: 480px){\n  .main-service .content .content-right{padding: 10px 10px 0 10px;}\n  .main-service .content .content-right p{line-height: 24px;}\n  .main-news .content .news-panel p.read-push{font-size: 12px;}\n  .main-case .content{padding-top: 60px;}\n  .main-case .content p.lable{padding-top: 10px; font-size: 18px; line-height: 48px;}\n  .main-case .content p{font-size: 12px; line-height: 20px; color: #505050;}\n  .main-about ul.aboutab{padding: 70px 0;}\n  .main-about ul.aboutab li{padding: 0 15px; font-size: 16px; box-sizing: border-box;}\n  .main-about .tabIntro .content .img{width: 100%;}\n  .main-about .tabIntro .content .panel{width: 100%;}\n  .main-about .tabIntro .content .panel.p_block{display: none;}\n  .main-about .tabIntro .p_hidden{display: block;}\n  .main-news #newsPage .layui-laypage a,.main-news #newsPage .layui-laypage span\n  ,.main-case #casePage .layui-laypage a,.main-case #casePage .layui-laypage span{padding: 0 12px; font-size: 14px; line-height: 30px; height: 30px; margin-right: 4px;}\n}\n/*小屏幕*/\n@media screen and (min-width: 768px){\n  .nav{max-height: 80px;}\n  .nav.index{background: rgba(255, 255, 255 ,0.3);}\n  .nav .nav-list button{display: none;}\n  .nav .layui-nav{width: auto; position: absolute; top: 0; padding: 0 5px; border-radius: 0; margin: 0;}\n  .nav .layui-nav .layui-nav-item{display: inline-block; margin:0 53px; line-height: 80px;}\n  .main-product p.title\n  ,.main-service p.title{font-size: 36px; line-height: 216px;}\n  .main.product .content .content-img{text-align: left;}\n  .main-news .content .news-panel strong a{font-size: 20px; line-height: 30px;}\n  .main-news .content .news-panel p.read-push{padding-top: 0; position: absolute; bottom: 40px;}\n  .main-newsdate .pushtime{line-height: 142px;}\n  .main-case .content{width: 45%;}\n  .main-case .content.even{margin-left: 9%;}\n  .main-about ul.aboutab li{padding: 0 32px; font-size: 24px; margin-left: 30px; line-height: 50px;}\n  .main-about .tabIntro .content p{padding: 0 30px; font-size: 18px; line-height: 30px;}\n  .main-about .tabJob .content p{font-size: 24px; line-height: 50px;}\n  .main-about .tabJob .content p.title{font-size: 30px; line-height: 90px;}\n  .main-about .tabJob .content ol li{font-size: 20px; line-height: 60px;}\n  .main-about .tabCour .timeline:before{left: 50%;}\n  .main-about .tabCour .timeline li{min-height: 195px; padding-top: 95px;}\n  .main-about .tabCour .timeline li .cour-img{left: 50%; margin-left: -97.5px; width: 195px;}\n  .main-about .tabCour .timeline li .cour-panel{padding-top: 55px; padding-left: 0;}\n  .main-about .tabCour .timeline li.odd .cour-panel{text-align: right;}\n}\n@media screen and (min-width: 768px) and (max-width: 992px){\n  .main.product .content div.right{padding-left: 20px;}\n  .nav .layui-nav .layui-nav-item{margin:0 33px;}\n  .main-service .content .content-right{padding: 10px 10px 0 15px;}\n  .main-service .content .content-right span{margin-bottom: 20px;}\n  .main-service .content .content-right p{line-height: 28px;}\n  .main.product .content .label{line-height: 40px; margin-top: 0;}\n  .main.product .content .detail{padding-bottom: 10px;}\n}\n/*大屏幕*/\n@media screen and (min-width: 992px){\n  .main.product .content{padding: 100px 0;}\n  .main.product .content div.right{padding-left: 0;}\n  .main-news .content .news-img{width: 20%;}\n  .main-news .content .news-panel{width: 80%;}\n  .main-case .content{width: 31%;}\n  .main-case .content.even{margin-left: 0;}\n  .main-case .content.center{margin-right: 3%; margin-left: 3%;}\n  .main-about .tabIntro .content p{padding: 0 50px; font-size: 20px; line-height: 40px;}\n}\n/*超大屏幕*/\n@media screen and (min-width: 1200px) {\n  .main-news .content .news-img{width: 35%;}\n  .main-news .content .news-panel{width: 65%;}\n  .main-news .content:nth-child(odd){padding-right: 20px;}\n  .main-news .content:nth-child(even){padding-left: 20px;}\n  .main-about .tabCour .timeline li .cour-panel{padding-left: 50px;}\n  .main-about .tabCour .timeline li.odd .cour-panel{padding-left: 0; padding-right: 50px;}\n}\n@media screen and (min-width: 1300px) {\n  .layui-container{width: 1200px; padding: 0;}\n  .main-about .tabJob .content:last-child{margin-bottom: 180px;}\n  .nav .nav-logo{position: absolute; top: 0; left: 0;}\n  .layui-col-space80{margin: -40px;}\n  .layui-col-space80>*{padding: 40px;}\n}\n"
  },
  {
    "path": "src/main/webapp/static/layui/css/layui.css",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n.layui-inline, img {\n    display: inline-block;\n    vertical-align: middle\n}\n\nh1, h2, h3, h4, h5, h6 {\n    font-weight: 400\n}\n\n.text-middle{\n    vertical-align: middle;\n    text-align: center;\n}\n\n.layui-edge, .layui-header, .layui-inline, .layui-main {\n    position: relative\n}\n\n.layui-body, .layui-edge, .layui-elip {\n    overflow: hidden\n}\n\n.layui-btn, .layui-edge, .layui-inline, img {\n    vertical-align: middle\n}\n\n.layui-btn, .layui-disabled, .layui-icon, .layui-unselect {\n    -moz-user-select: none;\n    -webkit-user-select: none;\n    -ms-user-select: none\n}\n\n.layui-elip, .layui-form-checkbox span, .layui-form-pane .layui-form-label {\n    text-overflow: ellipsis;\n    white-space: nowrap\n}\n\n.layui-breadcrumb, .layui-tree-btnGroup {\n    visibility: hidden\n}\n\nblockquote, body, button, dd, div, dl, dt, form, h1, h2, h3, h4, h5, h6, input, li, ol, p, pre, td, textarea, th, ul {\n    margin: 0;\n    padding: 0;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0)\n}\n\na:active, a:hover {\n    outline: 0\n}\n\nimg {\n    border: none\n}\n\nli {\n    list-style: none\n}\n\ntable {\n    border-collapse: collapse;\n    border-spacing: 0\n}\n\nh4, h5, h6 {\n    font-size: 100%\n}\n\nbutton, input, optgroup, option, select, textarea {\n    font-family: inherit;\n    font-size: inherit;\n    font-style: inherit;\n    font-weight: inherit;\n    outline: 0\n}\n\npre {\n    white-space: pre-wrap;\n    white-space: -moz-pre-wrap;\n    white-space: -pre-wrap;\n    white-space: -o-pre-wrap;\n    word-wrap: break-word\n}\n\nbody {\n    line-height: 24px;\n    font: 14px Helvetica Neue, Helvetica, PingFang SC, Tahoma, Arial, sans-serif\n}\n\nhr {\n    height: 1px;\n    margin: 2px 0;\n    border: 0;\n    clear: both\n}\n\na {\n    color: #333;\n    text-decoration: none\n}\n\na:hover {\n    color: #777\n}\n\na cite {\n    font-style: normal;\n    *cursor: pointer\n}\n\n.layui-border-box, .layui-border-box * {\n    box-sizing: border-box\n}\n\n.layui-box, .layui-box * {\n    box-sizing: content-box\n}\n\n.layui-clear {\n    clear: both;\n    *zoom: 1\n}\n\n.layui-clear:after {\n    content: '\\20';\n    clear: both;\n    *zoom: 1;\n    display: block;\n    height: 0\n}\n\n.layui-inline {\n    *display: inline;\n    *zoom: 1\n}\n\n.layui-edge {\n    display: inline-block;\n    width: 0;\n    height: 0;\n    border-width: 6px;\n    border-style: dashed;\n    border-color: transparent\n}\n\n.layui-edge-top {\n    top: -4px;\n    border-bottom-color: #999;\n    border-bottom-style: solid\n}\n\n.layui-edge-right {\n    border-left-color: #999;\n    border-left-style: solid\n}\n\n.layui-edge-bottom {\n    top: 2px;\n    border-top-color: #999;\n    border-top-style: solid\n}\n\n.layui-edge-left {\n    border-right-color: #999;\n    border-right-style: solid\n}\n\n.layui-disabled, .layui-disabled:hover {\n    color: #d2d2d2 !important;\n    cursor: not-allowed !important\n}\n\n.layui-circle {\n    border-radius: 100%\n}\n\n.layui-show {\n    display: block !important\n}\n\n.layui-hide {\n    display: none !important\n}\n\n@font-face {\n    font-family: layui-icon;\n    src: url(../font/iconfont.eot?v=250);\n    src: url(../font/iconfont.eot?v=250#iefix) format('embedded-opentype'), url(../font/iconfont.woff2?v=250) format('woff2'), url(../font/iconfont.woff?v=250) format('woff'), url(../font/iconfont.ttf?v=250) format('truetype'), url(../font/iconfont.svg?v=250#layui-icon) format('svg')\n}\n\n.layui-icon {\n    font-family: layui-icon !important;\n    font-size: 16px;\n    font-style: normal;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale\n}\n\n.layui-icon-reply-fill:before {\n    content: \"\\e611\"\n}\n\n.layui-icon-set-fill:before {\n    content: \"\\e614\"\n}\n\n.layui-icon-menu-fill:before {\n    content: \"\\e60f\"\n}\n\n.layui-icon-search:before {\n    content: \"\\e615\"\n}\n\n.layui-icon-share:before {\n    content: \"\\e641\"\n}\n\n.layui-icon-set-sm:before {\n    content: \"\\e620\"\n}\n\n.layui-icon-engine:before {\n    content: \"\\e628\"\n}\n\n.layui-icon-close:before {\n    content: \"\\1006\"\n}\n\n.layui-icon-close-fill:before {\n    content: \"\\1007\"\n}\n\n.layui-icon-chart-screen:before {\n    content: \"\\e629\"\n}\n\n.layui-icon-star:before {\n    content: \"\\e600\"\n}\n\n.layui-icon-circle-dot:before {\n    content: \"\\e617\"\n}\n\n.layui-icon-chat:before {\n    content: \"\\e606\"\n}\n\n.layui-icon-release:before {\n    content: \"\\e609\"\n}\n\n.layui-icon-list:before {\n    content: \"\\e60a\"\n}\n\n.layui-icon-chart:before {\n    content: \"\\e62c\"\n}\n\n.layui-icon-ok-circle:before {\n    content: \"\\1005\"\n}\n\n.layui-icon-layim-theme:before {\n    content: \"\\e61b\"\n}\n\n.layui-icon-table:before {\n    content: \"\\e62d\"\n}\n\n.layui-icon-right:before {\n    content: \"\\e602\"\n}\n\n.layui-icon-left:before {\n    content: \"\\e603\"\n}\n\n.layui-icon-cart-simple:before {\n    content: \"\\e698\"\n}\n\n.layui-icon-face-cry:before {\n    content: \"\\e69c\"\n}\n\n.layui-icon-face-smile:before {\n    content: \"\\e6af\"\n}\n\n.layui-icon-survey:before {\n    content: \"\\e6b2\"\n}\n\n.layui-icon-tree:before {\n    content: \"\\e62e\"\n}\n\n.layui-icon-upload-circle:before {\n    content: \"\\e62f\"\n}\n\n.layui-icon-add-circle:before {\n    content: \"\\e61f\"\n}\n\n.layui-icon-download-circle:before {\n    content: \"\\e601\"\n}\n\n.layui-icon-templeate-1:before {\n    content: \"\\e630\"\n}\n\n.layui-icon-util:before {\n    content: \"\\e631\"\n}\n\n.layui-icon-face-surprised:before {\n    content: \"\\e664\"\n}\n\n.layui-icon-edit:before {\n    content: \"\\e642\"\n}\n\n.layui-icon-speaker:before {\n    content: \"\\e645\"\n}\n\n.layui-icon-down:before {\n    content: \"\\e61a\"\n}\n\n.layui-icon-file:before {\n    content: \"\\e621\"\n}\n\n.layui-icon-layouts:before {\n    content: \"\\e632\"\n}\n\n.layui-icon-rate-half:before {\n    content: \"\\e6c9\"\n}\n\n.layui-icon-add-circle-fine:before {\n    content: \"\\e608\"\n}\n\n.layui-icon-prev-circle:before {\n    content: \"\\e633\"\n}\n\n.layui-icon-read:before {\n    content: \"\\e705\"\n}\n\n.layui-icon-404:before {\n    content: \"\\e61c\"\n}\n\n.layui-icon-carousel:before {\n    content: \"\\e634\"\n}\n\n.layui-icon-help:before {\n    content: \"\\e607\"\n}\n\n.layui-icon-code-circle:before {\n    content: \"\\e635\"\n}\n\n.layui-icon-water:before {\n    content: \"\\e636\"\n}\n\n.layui-icon-username:before {\n    content: \"\\e66f\"\n}\n\n.layui-icon-find-fill:before {\n    content: \"\\e670\"\n}\n\n.layui-icon-about:before {\n    content: \"\\e60b\"\n}\n\n.layui-icon-location:before {\n    content: \"\\e715\"\n}\n\n.layui-icon-up:before {\n    content: \"\\e619\"\n}\n\n.layui-icon-pause:before {\n    content: \"\\e651\"\n}\n\n.layui-icon-date:before {\n    content: \"\\e637\"\n}\n\n.layui-icon-layim-uploadfile:before {\n    content: \"\\e61d\"\n}\n\n.layui-icon-delete:before {\n    content: \"\\e640\"\n}\n\n.layui-icon-play:before {\n    content: \"\\e652\"\n}\n\n.layui-icon-top:before {\n    content: \"\\e604\"\n}\n\n.layui-icon-friends:before {\n    content: \"\\e612\"\n}\n\n.layui-icon-refresh-3:before {\n    content: \"\\e9aa\"\n}\n\n.layui-icon-ok:before {\n    content: \"\\e605\"\n}\n\n.layui-icon-layer:before {\n    content: \"\\e638\"\n}\n\n.layui-icon-face-smile-fine:before {\n    content: \"\\e60c\"\n}\n\n.layui-icon-dollar:before {\n    content: \"\\e659\"\n}\n\n.layui-icon-group:before {\n    content: \"\\e613\"\n}\n\n.layui-icon-layim-download:before {\n    content: \"\\e61e\"\n}\n\n.layui-icon-picture-fine:before {\n    content: \"\\e60d\"\n}\n\n.layui-icon-link:before {\n    content: \"\\e64c\"\n}\n\n.layui-icon-diamond:before {\n    content: \"\\e735\"\n}\n\n.layui-icon-log:before {\n    content: \"\\e60e\"\n}\n\n.layui-icon-rate-solid:before {\n    content: \"\\e67a\"\n}\n\n.layui-icon-fonts-del:before {\n    content: \"\\e64f\"\n}\n\n.layui-icon-unlink:before {\n    content: \"\\e64d\"\n}\n\n.layui-icon-fonts-clear:before {\n    content: \"\\e639\"\n}\n\n.layui-icon-triangle-r:before {\n    content: \"\\e623\"\n}\n\n.layui-icon-circle:before {\n    content: \"\\e63f\"\n}\n\n.layui-icon-radio:before {\n    content: \"\\e643\"\n}\n\n.layui-icon-align-center:before {\n    content: \"\\e647\"\n}\n\n.layui-icon-align-right:before {\n    content: \"\\e648\"\n}\n\n.layui-icon-align-left:before {\n    content: \"\\e649\"\n}\n\n.layui-icon-loading-1:before {\n    content: \"\\e63e\"\n}\n\n.layui-icon-return:before {\n    content: \"\\e65c\"\n}\n\n.layui-icon-fonts-strong:before {\n    content: \"\\e62b\"\n}\n\n.layui-icon-upload:before {\n    content: \"\\e67c\"\n}\n\n.layui-icon-dialogue:before {\n    content: \"\\e63a\"\n}\n\n.layui-icon-video:before {\n    content: \"\\e6ed\"\n}\n\n.layui-icon-headset:before {\n    content: \"\\e6fc\"\n}\n\n.layui-icon-cellphone-fine:before {\n    content: \"\\e63b\"\n}\n\n.layui-icon-add-1:before {\n    content: \"\\e654\"\n}\n\n.layui-icon-face-smile-b:before {\n    content: \"\\e650\"\n}\n\n.layui-icon-fonts-html:before {\n    content: \"\\e64b\"\n}\n\n.layui-icon-form:before {\n    content: \"\\e63c\"\n}\n\n.layui-icon-cart:before {\n    content: \"\\e657\"\n}\n\n.layui-icon-camera-fill:before {\n    content: \"\\e65d\"\n}\n\n.layui-icon-tabs:before {\n    content: \"\\e62a\"\n}\n\n.layui-icon-fonts-code:before {\n    content: \"\\e64e\"\n}\n\n.layui-icon-fire:before {\n    content: \"\\e756\"\n}\n\n.layui-icon-set:before {\n    content: \"\\e716\"\n}\n\n.layui-icon-fonts-u:before {\n    content: \"\\e646\"\n}\n\n.layui-icon-triangle-d:before {\n    content: \"\\e625\"\n}\n\n.layui-icon-tips:before {\n    content: \"\\e702\"\n}\n\n.layui-icon-picture:before {\n    content: \"\\e64a\"\n}\n\n.layui-icon-more-vertical:before {\n    content: \"\\e671\"\n}\n\n.layui-icon-flag:before {\n    content: \"\\e66c\"\n}\n\n.layui-icon-loading:before {\n    content: \"\\e63d\"\n}\n\n.layui-icon-fonts-i:before {\n    content: \"\\e644\"\n}\n\n.layui-icon-refresh-1:before {\n    content: \"\\e666\"\n}\n\n.layui-icon-rmb:before {\n    content: \"\\e65e\"\n}\n\n.layui-icon-home:before {\n    content: \"\\e68e\"\n}\n\n.layui-icon-user:before {\n    content: \"\\e770\"\n}\n\n.layui-icon-notice:before {\n    content: \"\\e667\"\n}\n\n.layui-icon-login-weibo:before {\n    content: \"\\e675\"\n}\n\n.layui-icon-voice:before {\n    content: \"\\e688\"\n}\n\n.layui-icon-upload-drag:before {\n    content: \"\\e681\"\n}\n\n.layui-icon-login-qq:before {\n    content: \"\\e676\"\n}\n\n.layui-icon-snowflake:before {\n    content: \"\\e6b1\"\n}\n\n.layui-icon-file-b:before {\n    content: \"\\e655\"\n}\n\n.layui-icon-template:before {\n    content: \"\\e663\"\n}\n\n.layui-icon-auz:before {\n    content: \"\\e672\"\n}\n\n.layui-icon-console:before {\n    content: \"\\e665\"\n}\n\n.layui-icon-app:before {\n    content: \"\\e653\"\n}\n\n.layui-icon-prev:before {\n    content: \"\\e65a\"\n}\n\n.layui-icon-website:before {\n    content: \"\\e7ae\"\n}\n\n.layui-icon-next:before {\n    content: \"\\e65b\"\n}\n\n.layui-icon-component:before {\n    content: \"\\e857\"\n}\n\n.layui-icon-more:before {\n    content: \"\\e65f\"\n}\n\n.layui-icon-login-wechat:before {\n    content: \"\\e677\"\n}\n\n.layui-icon-shrink-right:before {\n    content: \"\\e668\"\n}\n\n.layui-icon-spread-left:before {\n    content: \"\\e66b\"\n}\n\n.layui-icon-camera:before {\n    content: \"\\e660\"\n}\n\n.layui-icon-note:before {\n    content: \"\\e66e\"\n}\n\n.layui-icon-refresh:before {\n    content: \"\\e669\"\n}\n\n.layui-icon-female:before {\n    content: \"\\e661\"\n}\n\n.layui-icon-male:before {\n    content: \"\\e662\"\n}\n\n.layui-icon-password:before {\n    content: \"\\e673\"\n}\n\n.layui-icon-senior:before {\n    content: \"\\e674\"\n}\n\n.layui-icon-theme:before {\n    content: \"\\e66a\"\n}\n\n.layui-icon-tread:before {\n    content: \"\\e6c5\"\n}\n\n.layui-icon-praise:before {\n    content: \"\\e6c6\"\n}\n\n.layui-icon-star-fill:before {\n    content: \"\\e658\"\n}\n\n.layui-icon-rate:before {\n    content: \"\\e67b\"\n}\n\n.layui-icon-template-1:before {\n    content: \"\\e656\"\n}\n\n.layui-icon-vercode:before {\n    content: \"\\e679\"\n}\n\n.layui-icon-cellphone:before {\n    content: \"\\e678\"\n}\n\n.layui-icon-screen-full:before {\n    content: \"\\e622\"\n}\n\n.layui-icon-screen-restore:before {\n    content: \"\\e758\"\n}\n\n.layui-icon-cols:before {\n    content: \"\\e610\"\n}\n\n.layui-icon-export:before {\n    content: \"\\e67d\"\n}\n\n.layui-icon-print:before {\n    content: \"\\e66d\"\n}\n\n.layui-icon-slider:before {\n    content: \"\\e714\"\n}\n\n.layui-icon-addition:before {\n    content: \"\\e624\"\n}\n\n.layui-icon-subtraction:before {\n    content: \"\\e67e\"\n}\n\n.layui-icon-service:before {\n    content: \"\\e626\"\n}\n\n.layui-icon-transfer:before {\n    content: \"\\e691\"\n}\n\n.layui-main {\n    width: 1140px;\n    margin: 0 auto\n}\n\n.layui-header {\n    z-index: 1000;\n    height: 60px\n}\n\n.layui-header a:hover {\n    transition: all .5s;\n    -webkit-transition: all .5s\n}\n\n.layui-side {\n    position: fixed;\n    left: 0;\n    top: 0;\n    bottom: 0;\n    z-index: 999;\n    width: 200px;\n    overflow-x: hidden\n}\n\n.layui-side-scroll {\n    position: relative;\n    width: 220px;\n    height: 100%;\n    overflow-x: hidden\n}\n\n.layui-body {\n    position: absolute;\n    left: 200px;\n    right: 0;\n    top: 0;\n    bottom: 0;\n    z-index: 998;\n    width: auto;\n    overflow-y: auto;\n    box-sizing: border-box\n}\n\n.layui-layout-body {\n    overflow: hidden\n}\n\n.layui-layout-admin .layui-header {\n    background-color: #23262E\n}\n\n.layui-layout-admin .layui-side {\n    top: 60px;\n    width: 200px;\n    overflow-x: hidden\n}\n\n.layui-layout-admin .layui-body {\n    position: fixed;\n    top: 60px;\n    bottom: 44px\n}\n\n.layui-layout-admin .layui-main {\n    width: auto;\n    margin: 0 15px\n}\n\n.layui-layout-admin .layui-footer {\n    position: fixed;\n    left: 200px;\n    right: 0;\n    bottom: 0;\n    height: 44px;\n    line-height: 44px;\n    padding: 0 15px;\n    background-color: #eee\n}\n\n.layui-layout-admin .layui-logo {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 200px;\n    height: 100%;\n    line-height: 60px;\n    text-align: center;\n    color: #009688;\n    font-size: 16px\n}\n\n.layui-layout-admin .layui-header .layui-nav {\n    background: 0 0\n}\n\n.layui-layout-left {\n    position: absolute !important;\n    left: 200px;\n    top: 0\n}\n\n.layui-layout-right {\n    position: absolute !important;\n    right: 0;\n    top: 0\n}\n\n.layui-container {\n    position: relative;\n    margin: 0 auto;\n    padding: 0 15px;\n    box-sizing: border-box\n}\n\n.layui-fluid {\n    position: relative;\n    margin: 0 auto;\n    padding: 0 15px\n}\n\n.layui-row:after, .layui-row:before {\n    content: '';\n    display: block;\n    clear: both\n}\n\n.layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9, .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9, .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9, .layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 {\n    position: relative;\n    display: block;\n    box-sizing: border-box\n}\n\n.layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 {\n    float: left\n}\n\n.layui-col-xs1 {\n    width: 8.33333333%\n}\n\n.layui-col-xs2 {\n    width: 16.66666667%\n}\n\n.layui-col-xs3 {\n    width: 25%\n}\n\n.layui-col-xs4 {\n    width: 33.33333333%\n}\n\n.layui-col-xs5 {\n    width: 41.66666667%\n}\n\n.layui-col-xs6 {\n    width: 50%\n}\n\n.layui-col-xs7 {\n    width: 58.33333333%\n}\n\n.layui-col-xs8 {\n    width: 66.66666667%\n}\n\n.layui-col-xs9 {\n    width: 75%\n}\n\n.layui-col-xs10 {\n    width: 83.33333333%\n}\n\n.layui-col-xs11 {\n    width: 91.66666667%\n}\n\n.layui-col-xs12 {\n    width: 100%\n}\n\n.layui-col-xs-offset1 {\n    margin-left: 8.33333333%\n}\n\n.layui-col-xs-offset2 {\n    margin-left: 16.66666667%\n}\n\n.layui-col-xs-offset3 {\n    margin-left: 25%\n}\n\n.layui-col-xs-offset4 {\n    margin-left: 33.33333333%\n}\n\n.layui-col-xs-offset5 {\n    margin-left: 41.66666667%\n}\n\n.layui-col-xs-offset6 {\n    margin-left: 50%\n}\n\n.layui-col-xs-offset7 {\n    margin-left: 58.33333333%\n}\n\n.layui-col-xs-offset8 {\n    margin-left: 66.66666667%\n}\n\n.layui-col-xs-offset9 {\n    margin-left: 75%\n}\n\n.layui-col-xs-offset10 {\n    margin-left: 83.33333333%\n}\n\n.layui-col-xs-offset11 {\n    margin-left: 91.66666667%\n}\n\n.layui-col-xs-offset12 {\n    margin-left: 100%\n}\n\n@media screen and (max-width: 768px) {\n    .layui-hide-xs {\n        display: none !important\n    }\n\n    .layui-show-xs-block {\n        display: block !important\n    }\n\n    .layui-show-xs-inline {\n        display: inline !important\n    }\n\n    .layui-show-xs-inline-block {\n        display: inline-block !important\n    }\n}\n\n@media screen and (min-width: 768px) {\n    .layui-container {\n        width: 750px\n    }\n\n    .layui-hide-sm {\n        display: none !important\n    }\n\n    .layui-show-sm-block {\n        display: block !important\n    }\n\n    .layui-show-sm-inline {\n        display: inline !important\n    }\n\n    .layui-show-sm-inline-block {\n        display: inline-block !important\n    }\n\n    .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9 {\n        float: left\n    }\n\n    .layui-col-sm1 {\n        width: 8.33333333%\n    }\n\n    .layui-col-sm2 {\n        width: 16.66666667%\n    }\n\n    .layui-col-sm3 {\n        width: 25%\n    }\n\n    .layui-col-sm4 {\n        width: 33.33333333%\n    }\n\n    .layui-col-sm5 {\n        width: 41.66666667%\n    }\n\n    .layui-col-sm6 {\n        width: 50%\n    }\n\n    .layui-col-sm7 {\n        width: 58.33333333%\n    }\n\n    .layui-col-sm8 {\n        width: 66.66666667%\n    }\n\n    .layui-col-sm9 {\n        width: 75%\n    }\n\n    .layui-col-sm10 {\n        width: 83.33333333%\n    }\n\n    .layui-col-sm11 {\n        width: 91.66666667%\n    }\n\n    .layui-col-sm12 {\n        width: 100%\n    }\n\n    .layui-col-sm-offset1 {\n        margin-left: 8.33333333%\n    }\n\n    .layui-col-sm-offset2 {\n        margin-left: 16.66666667%\n    }\n\n    .layui-col-sm-offset3 {\n        margin-left: 25%\n    }\n\n    .layui-col-sm-offset4 {\n        margin-left: 33.33333333%\n    }\n\n    .layui-col-sm-offset5 {\n        margin-left: 41.66666667%\n    }\n\n    .layui-col-sm-offset6 {\n        margin-left: 50%\n    }\n\n    .layui-col-sm-offset7 {\n        margin-left: 58.33333333%\n    }\n\n    .layui-col-sm-offset8 {\n        margin-left: 66.66666667%\n    }\n\n    .layui-col-sm-offset9 {\n        margin-left: 75%\n    }\n\n    .layui-col-sm-offset10 {\n        margin-left: 83.33333333%\n    }\n\n    .layui-col-sm-offset11 {\n        margin-left: 91.66666667%\n    }\n\n    .layui-col-sm-offset12 {\n        margin-left: 100%\n    }\n}\n\n@media screen and (min-width: 992px) {\n    .layui-container {\n        width: 970px\n    }\n\n    .layui-hide-md {\n        display: none !important\n    }\n\n    .layui-show-md-block {\n        display: block !important\n    }\n\n    .layui-show-md-inline {\n        display: inline !important\n    }\n\n    .layui-show-md-inline-block {\n        display: inline-block !important\n    }\n\n    .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9 {\n        float: left\n    }\n\n    .layui-col-md1 {\n        width: 8.33333333%\n    }\n\n    .layui-col-md2 {\n        width: 16.66666667%\n    }\n\n    .layui-col-md3 {\n        width: 25%\n    }\n\n    .layui-col-md4 {\n        width: 33.33333333%\n    }\n\n    .layui-col-md5 {\n        width: 41.66666667%\n    }\n\n    .layui-col-md6 {\n        width: 50%\n    }\n\n    .layui-col-md7 {\n        width: 58.33333333%\n    }\n\n    .layui-col-md8 {\n        width: 66.66666667%\n    }\n\n    .layui-col-md9 {\n        width: 75%\n    }\n\n    .layui-col-md10 {\n        width: 83.33333333%\n    }\n\n    .layui-col-md11 {\n        width: 91.66666667%\n    }\n\n    .layui-col-md12 {\n        width: 100%\n    }\n\n    .layui-col-md-offset1 {\n        margin-left: 8.33333333%\n    }\n\n    .layui-col-md-offset2 {\n        margin-left: 16.66666667%\n    }\n\n    .layui-col-md-offset3 {\n        margin-left: 25%\n    }\n\n    .layui-col-md-offset4 {\n        margin-left: 33.33333333%\n    }\n\n    .layui-col-md-offset5 {\n        margin-left: 41.66666667%\n    }\n\n    .layui-col-md-offset6 {\n        margin-left: 50%\n    }\n\n    .layui-col-md-offset7 {\n        margin-left: 58.33333333%\n    }\n\n    .layui-col-md-offset8 {\n        margin-left: 66.66666667%\n    }\n\n    .layui-col-md-offset9 {\n        margin-left: 75%\n    }\n\n    .layui-col-md-offset10 {\n        margin-left: 83.33333333%\n    }\n\n    .layui-col-md-offset11 {\n        margin-left: 91.66666667%\n    }\n\n    .layui-col-md-offset12 {\n        margin-left: 100%\n    }\n}\n\n@media screen and (min-width: 1200px) {\n    .layui-container {\n        width: 1170px\n    }\n\n    .layui-hide-lg {\n        display: none !important\n    }\n\n    .layui-show-lg-block {\n        display: block !important\n    }\n\n    .layui-show-lg-inline {\n        display: inline !important\n    }\n\n    .layui-show-lg-inline-block {\n        display: inline-block !important\n    }\n\n    .layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9 {\n        float: left\n    }\n\n    .layui-col-lg1 {\n        width: 8.33333333%\n    }\n\n    .layui-col-lg2 {\n        width: 16.66666667%\n    }\n\n    .layui-col-lg3 {\n        width: 25%\n    }\n\n    .layui-col-lg4 {\n        width: 33.33333333%\n    }\n\n    .layui-col-lg5 {\n        width: 41.66666667%\n    }\n\n    .layui-col-lg6 {\n        width: 50%\n    }\n\n    .layui-col-lg7 {\n        width: 58.33333333%\n    }\n\n    .layui-col-lg8 {\n        width: 66.66666667%\n    }\n\n    .layui-col-lg9 {\n        width: 75%\n    }\n\n    .layui-col-lg10 {\n        width: 83.33333333%\n    }\n\n    .layui-col-lg11 {\n        width: 91.66666667%\n    }\n\n    .layui-col-lg12 {\n        width: 100%\n    }\n\n    .layui-col-lg-offset1 {\n        margin-left: 8.33333333%\n    }\n\n    .layui-col-lg-offset2 {\n        margin-left: 16.66666667%\n    }\n\n    .layui-col-lg-offset3 {\n        margin-left: 25%\n    }\n\n    .layui-col-lg-offset4 {\n        margin-left: 33.33333333%\n    }\n\n    .layui-col-lg-offset5 {\n        margin-left: 41.66666667%\n    }\n\n    .layui-col-lg-offset6 {\n        margin-left: 50%\n    }\n\n    .layui-col-lg-offset7 {\n        margin-left: 58.33333333%\n    }\n\n    .layui-col-lg-offset8 {\n        margin-left: 66.66666667%\n    }\n\n    .layui-col-lg-offset9 {\n        margin-left: 75%\n    }\n\n    .layui-col-lg-offset10 {\n        margin-left: 83.33333333%\n    }\n\n    .layui-col-lg-offset11 {\n        margin-left: 91.66666667%\n    }\n\n    .layui-col-lg-offset12 {\n        margin-left: 100%\n    }\n}\n\n.layui-col-space1 {\n    margin: -.5px\n}\n\n.layui-col-space1 > * {\n    padding: .5px\n}\n\n.layui-col-space3 {\n    margin: -1.5px\n}\n\n.layui-col-space3 > * {\n    padding: 1.5px\n}\n\n.layui-col-space5 {\n    margin: -2.5px\n}\n\n.layui-col-space5 > * {\n    padding: 2.5px\n}\n\n.layui-col-space8 {\n    margin: -3.5px\n}\n\n.layui-col-space8 > * {\n    padding: 3.5px\n}\n\n.layui-col-space10 {\n    margin: -5px\n}\n\n.layui-col-space10 > * {\n    padding: 5px\n}\n\n.layui-col-space12 {\n    margin: -6px\n}\n\n.layui-col-space12 > * {\n    padding: 6px\n}\n\n.layui-col-space15 {\n    margin: -7.5px\n}\n\n.layui-col-space15 > * {\n    padding: 7.5px\n}\n\n.layui-col-space18 {\n    margin: -9px\n}\n\n.layui-col-space18 > * {\n    padding: 9px\n}\n\n.layui-col-space20 {\n    margin: -10px\n}\n\n.layui-col-space20 > * {\n    padding: 10px\n}\n\n.layui-col-space22 {\n    margin: -11px\n}\n\n.layui-col-space22 > * {\n    padding: 11px\n}\n\n.layui-col-space25 {\n    margin: -12.5px\n}\n\n.layui-col-space25 > * {\n    padding: 12.5px\n}\n\n.layui-col-space30 {\n    margin: -15px\n}\n\n.layui-col-space30 > * {\n    padding: 15px\n}\n\n.layui-btn, .layui-input, .layui-select, .layui-textarea, .layui-upload-button {\n    outline: 0;\n    -webkit-appearance: none;\n    transition: all .3s;\n    -webkit-transition: all .3s;\n    box-sizing: border-box\n}\n\n.layui-elem-quote {\n    margin-bottom: 10px;\n    padding: 15px;\n    line-height: 22px;\n    border-left: 5px solid #009688;\n    border-radius: 0 2px 2px 0;\n    background-color: #f2f2f2\n}\n\n.layui-quote-nm {\n    border-style: solid;\n    border-width: 1px 1px 1px 5px;\n    background: 0 0\n}\n\n.layui-elem-field {\n    margin-bottom: 10px;\n    padding: 0;\n    border-width: 1px;\n    border-style: solid\n}\n\n.layui-elem-field legend {\n    margin-left: 20px;\n    padding: 0 10px;\n    font-size: 20px;\n    font-weight: 300\n}\n\n.layui-field-title {\n    margin: 10px 0 20px;\n    border-width: 1px 0 0\n}\n\n.layui-field-box {\n    padding: 10px 15px\n}\n\n.layui-field-title .layui-field-box {\n    padding: 10px 0\n}\n\n.layui-progress {\n    position: relative;\n    height: 6px;\n    border-radius: 20px;\n    background-color: #e2e2e2\n}\n\n.layui-progress-bar {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 0;\n    max-width: 100%;\n    height: 6px;\n    border-radius: 20px;\n    text-align: right;\n    background-color: #5FB878;\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-progress-big, .layui-progress-big .layui-progress-bar {\n    height: 18px;\n    line-height: 18px\n}\n\n.layui-progress-text {\n    position: relative;\n    top: -20px;\n    line-height: 18px;\n    font-size: 12px;\n    color: #666\n}\n\n.layui-progress-big .layui-progress-text {\n    position: static;\n    padding: 0 10px;\n    color: #fff\n}\n\n.layui-collapse {\n    border-width: 1px;\n    border-style: solid;\n    border-radius: 2px\n}\n\n.layui-colla-content, .layui-colla-item {\n    border-top-width: 1px;\n    border-top-style: solid\n}\n\n.layui-colla-item:first-child {\n    border-top: none\n}\n\n.layui-colla-title {\n    position: relative;\n    height: 42px;\n    line-height: 42px;\n    padding: 0 15px 0 35px;\n    color: #333;\n    background-color: #f2f2f2;\n    cursor: pointer;\n    font-size: 14px;\n    overflow: hidden\n}\n\n.layui-colla-content {\n    display: none;\n    padding: 10px 15px;\n    line-height: 22px;\n    color: #666\n}\n\n.layui-colla-icon {\n    position: absolute;\n    left: 15px;\n    top: 0;\n    font-size: 14px\n}\n\n.layui-card {\n    margin-bottom: 15px;\n    border-radius: 2px;\n    background-color: #fff;\n    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .05)\n}\n\n.layui-card:last-child {\n    margin-bottom: 0\n}\n\n.layui-card-header {\n    position: relative;\n    height: 42px;\n    line-height: 42px;\n    padding: 0 15px;\n    border-bottom: 1px solid #f6f6f6;\n    color: #333;\n    border-radius: 2px 2px 0 0;\n    font-size: 14px\n}\n\n.layui-bg-black, .layui-bg-blue, .layui-bg-cyan, .layui-bg-green, .layui-bg-orange, .layui-bg-red {\n    color: #fff !important\n}\n\n.layui-card-body {\n    position: relative;\n    padding: 10px 15px;\n    line-height: 24px\n}\n\n.layui-card-body[pad15] {\n    padding: 15px\n}\n\n.layui-card-body[pad20] {\n    padding: 20px\n}\n\n.layui-card-body .layui-table {\n    margin: 5px 0\n}\n\n.layui-card .layui-tab {\n    margin: 0\n}\n\n.layui-panel-window {\n    position: relative;\n    padding: 15px;\n    border-radius: 0;\n    border-top: 5px solid #E6E6E6;\n    background-color: #fff\n}\n\n.layui-auxiliar-moving {\n    position: fixed;\n    left: 0;\n    right: 0;\n    top: 0;\n    bottom: 0;\n    width: 100%;\n    height: 100%;\n    background: 0 0;\n    z-index: 9999999999\n}\n\n.layui-form-label, .layui-form-mid, .layui-form-select, .layui-input-block, .layui-input-inline, .layui-textarea {\n    position: relative\n}\n\n.layui-bg-red {\n    background-color: #FF5722 !important\n}\n\n.layui-bg-orange {\n    background-color: #FFB800 !important\n}\n\n.layui-bg-green {\n    background-color: #009688 !important\n}\n\n.layui-bg-cyan {\n    background-color: #2F4056 !important\n}\n\n.layui-bg-blue {\n    background-color: #1E9FFF !important\n}\n\n.layui-bg-black {\n    background-color: rgba(0, 141, 134, 0.9) !important\n}\n\n.layui-bg-gray {\n    background-color: #eee !important;\n    color: #666 !important\n}\n\n.layui-badge-rim, .layui-colla-content, .layui-colla-item, .layui-collapse, .layui-elem-field, .layui-form-pane .layui-form-item[pane], .layui-form-pane .layui-form-label, .layui-input, .layui-layedit, .layui-layedit-tool, .layui-quote-nm, .layui-select, .layui-tab-bar, .layui-tab-card, .layui-tab-title, .layui-tab-title .layui-this:after, .layui-textarea {\n    border-color: #e6e6e6\n}\n\n.layui-timeline-item:before, hr {\n    background-color: #e6e6e6\n}\n\n.layui-text {\n    line-height: 22px;\n    font-size: 14px;\n    color: #666\n}\n\n.layui-text h1, .layui-text h2, .layui-text h3 {\n    font-weight: 500;\n    color: #333\n}\n\n.layui-text h1 {\n    font-size: 30px\n}\n\n.layui-text h2 {\n    font-size: 24px\n}\n\n.layui-text h3 {\n    font-size: 18px\n}\n\n.layui-text a:not(.layui-btn) {\n    color: #01AAED\n}\n\n.layui-text a:not(.layui-btn):hover {\n    text-decoration: underline\n}\n\n.layui-text ul {\n    padding: 5px 0 5px 15px\n}\n\n.layui-text ul li {\n    margin-top: 5px;\n    list-style-type: disc\n}\n\n.layui-text em, .layui-word-aux {\n    color: #999 !important;\n    padding: 0 5px !important\n}\n\n.layui-btn {\n    display: inline-block;\n    height: 38px;\n    line-height: 38px;\n    padding: 0 18px;\n    background-color: #009688;\n    color: #fff;\n    white-space: nowrap;\n    text-align: center;\n    font-size: 14px;\n    border: none;\n    border-radius: 2px;\n    cursor: pointer\n}\n\n.layui-btn:hover {\n    opacity: .8;\n    filter: alpha(opacity=80);\n    color: #fff\n}\n\n.layui-btn:active {\n    opacity: 1;\n    filter: alpha(opacity=100)\n}\n\n.layui-btn + .layui-btn {\n    margin-left: 10px\n}\n\n.layui-btn-container {\n    font-size: 0\n}\n\n.layui-btn-container .layui-btn {\n    margin-right: 10px;\n    margin-bottom: 10px\n}\n\n.layui-btn-container .layui-btn + .layui-btn {\n    margin-left: 0\n}\n\n.layui-table .layui-btn-container .layui-btn {\n    margin-bottom: 9px\n}\n\n.layui-btn-radius {\n    border-radius: 100px\n}\n\n.layui-btn .layui-icon {\n    margin-right: 3px;\n    font-size: 18px;\n    vertical-align: bottom;\n    vertical-align: middle \\9\n}\n\n.layui-btn-primary {\n    border: 1px solid #C9C9C9;\n    background-color: #fff;\n    color: #555\n}\n\n.layui-btn-primary:hover {\n    border-color: #009688;\n    color: #333\n}\n\n.layui-btn-normal {\n    background-color: #1E9FFF\n}\n\n.layui-btn-warm {\n    background-color: #FFB800\n}\n\n.layui-btn-danger {\n    background-color: #FF5722\n}\n\n.layui-btn-checked {\n    background-color: #5FB878\n}\n\n.layui-btn-disabled, .layui-btn-disabled:active, .layui-btn-disabled:hover {\n    border: 1px solid #e6e6e6;\n    background-color: #FBFBFB;\n    color: #C9C9C9;\n    cursor: not-allowed;\n    opacity: 1\n}\n\n.layui-btn-lg {\n    height: 44px;\n    line-height: 44px;\n    padding: 0 25px;\n    font-size: 16px\n}\n\n.layui-btn-sm {\n    height: 30px;\n    line-height: 30px;\n    padding: 0 10px;\n    font-size: 12px\n}\n\n.layui-btn-sm i {\n    font-size: 16px !important\n}\n\n.layui-btn-xs {\n    height: 22px;\n    line-height: 22px;\n    padding: 0 5px;\n    font-size: 12px\n}\n\n.layui-btn-xs i {\n    font-size: 14px !important\n}\n\n.layui-btn-group {\n    display: inline-block;\n    vertical-align: middle;\n    font-size: 0\n}\n\n.layui-btn-group .layui-btn {\n    margin-left: 0 !important;\n    margin-right: 0 !important;\n    border-left: 1px solid rgba(255, 255, 255, .5);\n    border-radius: 0\n}\n\n.layui-btn-group .layui-btn-primary {\n    border-left: none\n}\n\n.layui-btn-group .layui-btn-primary:hover {\n    border-color: #C9C9C9;\n    color: #009688\n}\n\n.layui-btn-group .layui-btn:first-child {\n    border-left: none;\n    border-radius: 2px 0 0 2px\n}\n\n.layui-btn-group .layui-btn-primary:first-child {\n    border-left: 1px solid #c9c9c9\n}\n\n.layui-btn-group .layui-btn:last-child {\n    border-radius: 0 2px 2px 0\n}\n\n.layui-btn-group .layui-btn + .layui-btn {\n    margin-left: 0\n}\n\n.layui-btn-group + .layui-btn-group {\n    margin-left: 10px\n}\n\n.layui-btn-fluid {\n    width: 100%\n}\n\n.layui-input, .layui-select, .layui-textarea {\n    height: 38px;\n    line-height: 1.3;\n    line-height: 38px \\9;\n    border-width: 1px;\n    border-style: solid;\n    background-color: #fff;\n    border-radius: 2px\n}\n\n.layui-input::-webkit-input-placeholder, .layui-select::-webkit-input-placeholder, .layui-textarea::-webkit-input-placeholder {\n    line-height: 1.3\n}\n\n.layui-input, .layui-textarea {\n    display: block;\n    width: 100%;\n    padding-left: 10px\n}\n\n.layui-input:hover, .layui-textarea:hover {\n    border-color: #D2D2D2 !important\n}\n\n.layui-input:focus, .layui-textarea:focus {\n    border-color: #C9C9C9 !important\n}\n\n.layui-textarea {\n    min-height: 100px;\n    height: auto;\n    line-height: 20px;\n    padding: 6px 10px;\n    resize: vertical\n}\n\n.layui-select {\n    padding: 0 10px\n}\n\n.layui-form input[type=checkbox], .layui-form input[type=radio], .layui-form select {\n    display: none\n}\n\n.layui-form [lay-ignore] {\n    display: initial\n}\n\n.layui-form-item {\n    margin-bottom: 15px;\n    clear: both;\n    *zoom: 1\n}\n\n.layui-form-item:after {\n    content: '\\20';\n    clear: both;\n    *zoom: 1;\n    display: block;\n    height: 0\n}\n\n.layui-form-label {\n    float: left;\n    display: block;\n    padding: 9px 15px;\n    width: 80px;\n    font-weight: 400;\n    line-height: 20px;\n    text-align: right\n}\n\n.layui-form-label-col {\n    display: block;\n    float: none;\n    padding: 9px 0;\n    line-height: 20px;\n    text-align: left\n}\n\n.layui-form-item .layui-inline {\n    margin-bottom: 5px;\n    margin-right: 10px\n}\n\n.layui-input-block {\n    margin-left: 110px;\n    min-height: 36px\n}\n\n.layui-input-inline {\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-form-item .layui-input-inline {\n    float: left;\n    width: 190px;\n    margin-right: 10px\n}\n\n.layui-form-text .layui-input-inline {\n    width: auto\n}\n\n.layui-form-mid {\n    float: left;\n    display: block;\n    padding: 9px 0 !important;\n    line-height: 20px;\n    margin-right: 10px\n}\n\n.layui-form-danger + .layui-form-select .layui-input, .layui-form-danger:focus {\n    border-color: #FF5722 !important\n}\n\n.layui-form-select .layui-input {\n    padding-right: 30px;\n    cursor: pointer\n}\n\n.layui-form-select .layui-edge {\n    position: absolute;\n    right: 10px;\n    top: 50%;\n    margin-top: -3px;\n    cursor: pointer;\n    border-width: 6px;\n    border-top-color: #c2c2c2;\n    border-top-style: solid;\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-form-select dl {\n    display: none;\n    position: absolute;\n    left: 0;\n    top: 42px;\n    padding: 5px 0;\n    z-index: 899;\n    min-width: 100%;\n    border: 1px solid #d2d2d2;\n    max-height: 300px;\n    overflow-y: auto;\n    background-color: #fff;\n    border-radius: 2px;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, .12);\n    box-sizing: border-box\n}\n\n.layui-form-select dl dd, .layui-form-select dl dt {\n    padding: 0 10px;\n    line-height: 36px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis\n}\n\n.layui-form-select dl dt {\n    font-size: 12px;\n    color: #999\n}\n\n.layui-form-select dl dd {\n    cursor: pointer\n}\n\n.layui-form-select dl dd:hover {\n    background-color: #f2f2f2;\n    -webkit-transition: .5s all;\n    transition: .5s all\n}\n\n.layui-form-select .layui-select-group dd {\n    padding-left: 20px\n}\n\n.layui-form-select dl dd.layui-select-tips {\n    padding-left: 10px !important;\n    color: #999\n}\n\n.layui-form-select dl dd.layui-this {\n    background-color: #5FB878;\n    color: #fff\n}\n\n.layui-form-checkbox, .layui-form-select dl dd.layui-disabled {\n    background-color: #fff\n}\n\n.layui-form-selected dl {\n    display: block\n}\n\n.layui-form-checkbox, .layui-form-checkbox *, .layui-form-switch {\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-form-selected .layui-edge {\n    margin-top: -9px;\n    -webkit-transform: rotate(180deg);\n    transform: rotate(180deg);\n    margin-top: -3px \\9\n}\n\n:root .layui-form-selected .layui-edge {\n    margin-top: -9px \\0/ IE9\n}\n\n.layui-form-selectup dl {\n    top: auto;\n    bottom: 42px\n}\n\n.layui-select-none {\n    margin: 5px 0;\n    text-align: center;\n    color: #999\n}\n\n.layui-select-disabled .layui-disabled {\n    border-color: #eee !important\n}\n\n.layui-select-disabled .layui-edge {\n    border-top-color: #d2d2d2\n}\n\n.layui-form-checkbox {\n    position: relative;\n    height: 30px;\n    line-height: 30px;\n    margin-right: 10px;\n    padding-right: 30px;\n    cursor: pointer;\n    font-size: 0;\n    -webkit-transition: .1s linear;\n    transition: .1s linear;\n    box-sizing: border-box\n}\n\n.layui-form-checkbox span {\n    padding: 0 10px;\n    height: 100%;\n    font-size: 14px;\n    border-radius: 2px 0 0 2px;\n    background-color: #d2d2d2;\n    color: #fff;\n    overflow: hidden\n}\n\n.layui-form-checkbox:hover span {\n    background-color: #c2c2c2\n}\n\n.layui-form-checkbox i {\n    position: absolute;\n    right: 0;\n    top: 0;\n    width: 30px;\n    height: 28px;\n    border: 1px solid #d2d2d2;\n    border-left: none;\n    border-radius: 0 2px 2px 0;\n    color: #fff;\n    font-size: 20px;\n    text-align: center\n}\n\n.layui-form-checkbox:hover i {\n    border-color: #c2c2c2;\n    color: #c2c2c2\n}\n\n.layui-form-checked, .layui-form-checked:hover {\n    border-color: #5FB878\n}\n\n.layui-form-checked span, .layui-form-checked:hover span {\n    background-color: #5FB878\n}\n\n.layui-form-checked i, .layui-form-checked:hover i {\n    color: #5FB878\n}\n\n.layui-form-item .layui-form-checkbox {\n    margin-top: 4px\n}\n\n.layui-form-checkbox[lay-skin=primary] {\n    height: auto !important;\n    line-height: normal !important;\n    min-width: 18px;\n    min-height: 18px;\n    border: none !important;\n    margin-right: 0;\n    padding-left: 28px;\n    padding-right: 0;\n    background: 0 0\n}\n\n.layui-form-checkbox[lay-skin=primary] span {\n    padding-left: 0;\n    padding-right: 15px;\n    line-height: 18px;\n    background: 0 0;\n    color: #666\n}\n\n.layui-form-checkbox[lay-skin=primary] i {\n    right: auto;\n    left: 0;\n    width: 16px;\n    height: 16px;\n    line-height: 16px;\n    border: 1px solid #d2d2d2;\n    font-size: 12px;\n    border-radius: 2px;\n    background-color: #fff;\n    -webkit-transition: .1s linear;\n    transition: .1s linear\n}\n\n.layui-form-checkbox[lay-skin=primary]:hover i {\n    border-color: #5FB878;\n    color: #fff\n}\n\n.layui-form-checked[lay-skin=primary] i {\n    border-color: #5FB878 !important;\n    background-color: #5FB878;\n    color: #fff\n}\n\n.layui-checkbox-disbaled[lay-skin=primary] span {\n    background: 0 0 !important;\n    color: #c2c2c2\n}\n\n.layui-checkbox-disbaled[lay-skin=primary]:hover i {\n    border-color: #d2d2d2\n}\n\n.layui-form-item .layui-form-checkbox[lay-skin=primary] {\n    margin-top: 10px\n}\n\n.layui-form-switch {\n    position: relative;\n    height: 22px;\n    line-height: 22px;\n    min-width: 35px;\n    padding: 0 5px;\n    margin-top: 8px;\n    border: 1px solid #d2d2d2;\n    border-radius: 20px;\n    cursor: pointer;\n    background-color: #fff;\n    -webkit-transition: .1s linear;\n    transition: .1s linear\n}\n\n.layui-form-switch i {\n    position: absolute;\n    left: 5px;\n    top: 3px;\n    width: 16px;\n    height: 16px;\n    border-radius: 20px;\n    background-color: #d2d2d2;\n    -webkit-transition: .1s linear;\n    transition: .1s linear\n}\n\n.layui-form-switch em {\n    position: relative;\n    top: 0;\n    width: 25px;\n    margin-left: 21px;\n    padding: 0 !important;\n    text-align: center !important;\n    color: #999 !important;\n    font-style: normal !important;\n    font-size: 12px\n}\n\n.layui-form-onswitch {\n    border-color: #5FB878;\n    background-color: #5FB878\n}\n\n.layui-checkbox-disbaled, .layui-checkbox-disbaled i {\n    border-color: #e2e2e2 !important\n}\n\n.layui-form-onswitch i {\n    left: 100%;\n    margin-left: -21px;\n    background-color: #fff\n}\n\n.layui-form-onswitch em {\n    margin-left: 5px;\n    margin-right: 21px;\n    color: #fff !important\n}\n\n.layui-checkbox-disbaled span {\n    background-color: #e2e2e2 !important\n}\n\n.layui-checkbox-disbaled:hover i {\n    color: #fff !important\n}\n\n[lay-radio] {\n    display: none\n}\n\n.layui-form-radio, .layui-form-radio * {\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-form-radio {\n    line-height: 28px;\n    margin: 6px 10px 0 0;\n    padding-right: 10px;\n    cursor: pointer;\n    font-size: 0\n}\n\n.layui-form-radio * {\n    font-size: 14px\n}\n\n.layui-form-radio > i {\n    margin-right: 8px;\n    font-size: 22px;\n    color: #c2c2c2\n}\n\n.layui-form-radio > i:hover, .layui-form-radioed > i {\n    color: #5FB878\n}\n\n.layui-radio-disbaled > i {\n    color: #e2e2e2 !important\n}\n\n.layui-form-pane .layui-form-label {\n    width: 110px;\n    padding: 8px 15px;\n    height: 38px;\n    line-height: 20px;\n    border-width: 1px;\n    border-style: solid;\n    border-radius: 2px 0 0 2px;\n    text-align: center;\n    background-color: #FBFBFB;\n    overflow: hidden;\n    box-sizing: border-box\n}\n\n.layui-form-pane .layui-input-inline {\n    margin-left: -1px\n}\n\n.layui-form-pane .layui-input-block {\n    margin-left: 110px;\n    left: -1px\n}\n\n.layui-form-pane .layui-input {\n    border-radius: 0 2px 2px 0\n}\n\n.layui-form-pane .layui-form-text .layui-form-label {\n    float: none;\n    width: 100%;\n    border-radius: 2px;\n    box-sizing: border-box;\n    text-align: left\n}\n\n.layui-form-pane .layui-form-text .layui-input-inline {\n    display: block;\n    margin: 0;\n    top: -1px;\n    clear: both\n}\n\n.layui-form-pane .layui-form-text .layui-input-block {\n    margin: 0;\n    left: 0;\n    top: -1px\n}\n\n.layui-form-pane .layui-form-text .layui-textarea {\n    min-height: 100px;\n    border-radius: 0 0 2px 2px\n}\n\n.layui-form-pane .layui-form-checkbox {\n    margin: 4px 0 4px 10px\n}\n\n.layui-form-pane .layui-form-radio, .layui-form-pane .layui-form-switch {\n    margin-top: 6px;\n    margin-left: 10px\n}\n\n.layui-form-pane .layui-form-item[pane] {\n    position: relative;\n    border-width: 1px;\n    border-style: solid\n}\n\n.layui-form-pane .layui-form-item[pane] .layui-form-label {\n    position: absolute;\n    left: 0;\n    top: 0;\n    height: 100%;\n    border-width: 0 1px 0 0\n}\n\n.layui-form-pane .layui-form-item[pane] .layui-input-inline {\n    margin-left: 110px\n}\n\n@media screen and (max-width: 450px) {\n    .layui-form-item .layui-form-label {\n        text-overflow: ellipsis;\n        overflow: hidden;\n        white-space: nowrap\n    }\n\n    .layui-form-item .layui-inline {\n        display: block;\n        margin-right: 0;\n        margin-bottom: 20px;\n        clear: both\n    }\n\n    .layui-form-item .layui-inline:after {\n        content: '\\20';\n        clear: both;\n        display: block;\n        height: 0\n    }\n\n    .layui-form-item .layui-input-inline {\n        display: block;\n        float: none;\n        left: -3px;\n        width: auto;\n        margin: 0 0 10px 112px\n    }\n\n    .layui-form-item .layui-input-inline + .layui-form-mid {\n        margin-left: 110px;\n        top: -5px;\n        padding: 0\n    }\n\n    .layui-form-item .layui-form-checkbox {\n        margin-right: 5px;\n        margin-bottom: 5px\n    }\n}\n\n.layui-layedit {\n    border-width: 1px;\n    border-style: solid;\n    border-radius: 2px\n}\n\n.layui-layedit-tool {\n    padding: 3px 5px;\n    border-bottom-width: 1px;\n    border-bottom-style: solid;\n    font-size: 0\n}\n\n.layedit-tool-fixed {\n    position: fixed;\n    top: 0;\n    border-top: 1px solid #e2e2e2\n}\n\n.layui-layedit-tool .layedit-tool-mid, .layui-layedit-tool .layui-icon {\n    display: inline-block;\n    vertical-align: middle;\n    text-align: center;\n    font-size: 14px\n}\n\n.layui-layedit-tool .layui-icon {\n    position: relative;\n    width: 32px;\n    height: 30px;\n    line-height: 30px;\n    margin: 3px 5px;\n    color: #777;\n    cursor: pointer;\n    border-radius: 2px\n}\n\n.layui-layedit-tool .layui-icon:hover {\n    color: #393D49\n}\n\n.layui-layedit-tool .layui-icon:active {\n    color: #000\n}\n\n.layui-layedit-tool .layedit-tool-active {\n    background-color: #e2e2e2;\n    color: #000\n}\n\n.layui-layedit-tool .layui-disabled, .layui-layedit-tool .layui-disabled:hover {\n    color: #d2d2d2;\n    cursor: not-allowed\n}\n\n.layui-layedit-tool .layedit-tool-mid {\n    width: 1px;\n    height: 18px;\n    margin: 0 10px;\n    background-color: #d2d2d2\n}\n\n.layedit-tool-html {\n    width: 50px !important;\n    font-size: 30px !important\n}\n\n.layedit-tool-b, .layedit-tool-code, .layedit-tool-help {\n    font-size: 16px !important\n}\n\n.layedit-tool-d, .layedit-tool-face, .layedit-tool-image, .layedit-tool-unlink {\n    font-size: 18px !important\n}\n\n.layedit-tool-image input {\n    position: absolute;\n    font-size: 0;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n    opacity: .01;\n    filter: Alpha(opacity=1);\n    cursor: pointer\n}\n\n.layui-layedit-iframe iframe {\n    display: block;\n    width: 100%\n}\n\n#LAY_layedit_code {\n    overflow: hidden\n}\n\n.layui-laypage {\n    display: inline-block;\n    *display: inline;\n    *zoom: 1;\n    vertical-align: middle;\n    margin: 10px 0;\n    font-size: 0\n}\n\n.layui-laypage > a:first-child, .layui-laypage > a:first-child em {\n    border-radius: 2px 0 0 2px\n}\n\n.layui-laypage > a:last-child, .layui-laypage > a:last-child em {\n    border-radius: 0 2px 2px 0\n}\n\n.layui-laypage > :first-child {\n    margin-left: 0 !important\n}\n\n.layui-laypage > :last-child {\n    margin-right: 0 !important\n}\n\n.layui-laypage a, .layui-laypage button, .layui-laypage input, .layui-laypage select, .layui-laypage span {\n    border: 1px solid #e2e2e2\n}\n\n.layui-laypage a, .layui-laypage span {\n    display: inline-block;\n    *display: inline;\n    *zoom: 1;\n    vertical-align: middle;\n    padding: 0 15px;\n    height: 28px;\n    line-height: 28px;\n    margin: 0 -1px 5px 0;\n    background-color: #fff;\n    color: #333;\n    font-size: 12px\n}\n\n.layui-flow-more a *, .layui-laypage input, .layui-table-view select[lay-ignore] {\n    display: inline-block\n}\n\n.layui-laypage a:hover {\n    color: #009688\n}\n\n.layui-laypage em {\n    font-style: normal\n}\n\n.layui-laypage .layui-laypage-spr {\n    color: #999;\n    font-weight: 700\n}\n\n.layui-laypage a {\n    text-decoration: none\n}\n\n.layui-laypage .layui-laypage-curr {\n    position: relative\n}\n\n.layui-laypage .layui-laypage-curr em {\n    position: relative;\n    color: #fff\n}\n\n.layui-laypage .layui-laypage-curr .layui-laypage-em {\n    position: absolute;\n    left: -1px;\n    top: -1px;\n    padding: 1px;\n    width: 100%;\n    height: 100%;\n    background-color: #009688\n}\n\n.layui-laypage-em {\n    border-radius: 2px\n}\n\n.layui-laypage-next em, .layui-laypage-prev em {\n    font-family: Sim sun;\n    font-size: 16px\n}\n\n.layui-laypage .layui-laypage-count, .layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh, .layui-laypage .layui-laypage-skip {\n    margin-left: 10px;\n    margin-right: 10px;\n    padding: 0;\n    border: none\n}\n\n.layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh {\n    vertical-align: top\n}\n\n.layui-laypage .layui-laypage-refresh i {\n    font-size: 18px;\n    cursor: pointer\n}\n\n.layui-laypage select {\n    height: 22px;\n    padding: 3px;\n    border-radius: 2px;\n    cursor: pointer\n}\n\n.layui-laypage .layui-laypage-skip {\n    height: 30px;\n    line-height: 30px;\n    color: #999\n}\n\n.layui-laypage button, .layui-laypage input {\n    height: 30px;\n    line-height: 30px;\n    border-radius: 2px;\n    vertical-align: top;\n    background-color: #fff;\n    box-sizing: border-box\n}\n\n.layui-laypage input {\n    width: 40px;\n    margin: 0 10px;\n    padding: 0 3px;\n    text-align: center\n}\n\n.layui-laypage input:focus, .layui-laypage select:focus {\n    border-color: #009688 !important\n}\n\n.layui-laypage button {\n    margin-left: 10px;\n    padding: 0 10px;\n    cursor: pointer\n}\n\n.layui-table, .layui-table-view {\n    margin: 10px 0\n}\n\n.layui-flow-more {\n    margin: 10px 0;\n    text-align: center;\n    color: #999;\n    font-size: 14px\n}\n\n.layui-flow-more a {\n    height: 32px;\n    line-height: 32px\n}\n\n.layui-flow-more a * {\n    vertical-align: top\n}\n\n.layui-flow-more a cite {\n    padding: 0 20px;\n    border-radius: 3px;\n    background-color: #eee;\n    color: #333;\n    font-style: normal\n}\n\n.layui-flow-more a cite:hover {\n    opacity: .8\n}\n\n.layui-flow-more a i {\n    font-size: 30px;\n    color: #737383\n}\n\n.layui-table {\n    width: 100%;\n    background-color: #fff;\n    color: #666\n}\n\n.layui-table tr {\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-table th {\n    text-align: left;\n    font-weight: 400\n}\n\n.layui-table tbody tr:hover, .layui-table thead tr, .layui-table-click, .layui-table-header, .layui-table-hover, .layui-table-mend, .layui-table-patch, .layui-table-tool, .layui-table-total, .layui-table-total tr, .layui-table[lay-even] tr:nth-child(even) {\n    background-color: #f2f2f2\n}\n\n.layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view, .layui-table[lay-skin=line], .layui-table[lay-skin=row] {\n    border-width: 1px;\n    border-style: solid;\n    border-color: #e6e6e6\n}\n\n.layui-table td, .layui-table th {\n    position: relative;\n    padding: 9px 15px;\n    min-height: 20px;\n    line-height: 20px;\n    font-size: 14px\n}\n\n.layui-table[lay-skin=line] td, .layui-table[lay-skin=line] th {\n    border-width: 0 0 1px\n}\n\n.layui-table[lay-skin=row] td, .layui-table[lay-skin=row] th {\n    border-width: 0 1px 0 0\n}\n\n.layui-table[lay-skin=nob] td, .layui-table[lay-skin=nob] th {\n    border: none\n}\n\n.layui-table img {\n    max-width: 100px\n}\n\n.layui-table[lay-size=lg] td, .layui-table[lay-size=lg] th {\n    padding: 15px 30px\n}\n\n.layui-table-view .layui-table[lay-size=lg] .layui-table-cell {\n    height: 40px;\n    line-height: 40px\n}\n\n.layui-table[lay-size=sm] td, .layui-table[lay-size=sm] th {\n    font-size: 12px;\n    padding: 5px 10px\n}\n\n.layui-table-view .layui-table[lay-size=sm] .layui-table-cell {\n    height: 20px;\n    line-height: 20px\n}\n\n.layui-table[lay-data] {\n    display: none\n}\n\n.layui-table-box {\n    position: relative;\n    overflow: hidden\n}\n\n.layui-table-view .layui-table {\n    position: relative;\n    width: auto;\n    margin: 0\n}\n\n.layui-table-view .layui-table[lay-skin=line] {\n    border-width: 0 1px 0 0\n}\n\n.layui-table-view .layui-table[lay-skin=row] {\n    border-width: 0 0 1px\n}\n\n.layui-table-view .layui-table td, .layui-table-view .layui-table th {\n    padding: 5px 0;\n    border-top: none;\n    border-left: none\n}\n\n.layui-table-view .layui-table th.layui-unselect .layui-table-cell span {\n    cursor: pointer\n}\n\n.layui-table-view .layui-table td {\n    cursor: default\n}\n\n.layui-table-view .layui-table td[data-edit=text] {\n    cursor: text\n}\n\n.layui-table-view .layui-form-checkbox[lay-skin=primary] i {\n    width: 18px;\n    height: 18px\n}\n\n.layui-table-view .layui-form-radio {\n    line-height: 0;\n    padding: 0\n}\n\n.layui-table-view .layui-form-radio > i {\n    margin: 0;\n    font-size: 20px\n}\n\n.layui-table-init {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n    text-align: center;\n    z-index: 110\n}\n\n.layui-table-init .layui-icon {\n    position: absolute;\n    left: 50%;\n    top: 50%;\n    margin: -15px 0 0 -15px;\n    font-size: 30px;\n    color: #c2c2c2\n}\n\n.layui-table-header {\n    border-width: 0 0 1px;\n    overflow: hidden\n}\n\n.layui-table-header .layui-table {\n    margin-bottom: -1px\n}\n\n.layui-table-tool .layui-inline[lay-event] {\n    position: relative;\n    width: 26px;\n    height: 26px;\n    padding: 5px;\n    line-height: 16px;\n    margin-right: 10px;\n    text-align: center;\n    color: #333;\n    border: 1px solid #ccc;\n    cursor: pointer;\n    -webkit-transition: .5s all;\n    transition: .5s all\n}\n\n.layui-table-tool .layui-inline[lay-event]:hover {\n    border: 1px solid #999\n}\n\n.layui-table-tool-temp {\n    padding-right: 120px\n}\n\n.layui-table-tool-self {\n    position: absolute;\n    right: 17px;\n    top: 10px\n}\n\n.layui-table-tool .layui-table-tool-self .layui-inline[lay-event] {\n    margin: 0 0 0 10px\n}\n\n.layui-table-tool-panel {\n    position: absolute;\n    top: 29px;\n    left: -1px;\n    padding: 5px 0;\n    min-width: 150px;\n    min-height: 40px;\n    border: 1px solid #d2d2d2;\n    text-align: left;\n    overflow-y: auto;\n    background-color: #fff;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, .12)\n}\n\n.layui-table-cell, .layui-table-tool-panel li {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap\n}\n\n.layui-table-tool-panel li {\n    padding: 0 10px;\n    line-height: 30px;\n    -webkit-transition: .5s all;\n    transition: .5s all\n}\n\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] {\n    width: 100%;\n    padding-left: 28px\n}\n\n.layui-table-tool-panel li:hover {\n    background-color: #f2f2f2\n}\n\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i {\n    position: absolute;\n    left: 0;\n    top: 0\n}\n\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span {\n    padding: 0\n}\n\n.layui-table-tool .layui-table-tool-self .layui-table-tool-panel {\n    left: auto;\n    right: -1px\n}\n\n.layui-table-col-set {\n    position: absolute;\n    right: 0;\n    top: 0;\n    width: 20px;\n    height: 100%;\n    border-width: 0 0 0 1px;\n    background-color: #fff\n}\n\n.layui-table-sort {\n    width: 10px;\n    height: 20px;\n    margin-left: 5px;\n    cursor: pointer !important\n}\n\n.layui-table-sort .layui-edge {\n    position: absolute;\n    left: 5px;\n    border-width: 5px\n}\n\n.layui-table-sort .layui-table-sort-asc {\n    top: 3px;\n    border-top: none;\n    border-bottom-style: solid;\n    border-bottom-color: #b2b2b2\n}\n\n.layui-table-sort .layui-table-sort-asc:hover {\n    border-bottom-color: #666\n}\n\n.layui-table-sort .layui-table-sort-desc {\n    bottom: 5px;\n    border-bottom: none;\n    border-top-style: solid;\n    border-top-color: #b2b2b2\n}\n\n.layui-table-sort .layui-table-sort-desc:hover {\n    border-top-color: #666\n}\n\n.layui-table-sort[lay-sort=asc] .layui-table-sort-asc {\n    border-bottom-color: #000\n}\n\n.layui-table-sort[lay-sort=desc] .layui-table-sort-desc {\n    border-top-color: #000\n}\n\n.layui-table-cell {\n    height: 28px;\n    line-height: 28px;\n    padding: 0 15px;\n    position: relative;\n    box-sizing: border-box\n}\n\n.layui-table-cell .layui-form-checkbox[lay-skin=primary] {\n    top: -1px;\n    padding: 0\n}\n\n.layui-table-cell .layui-table-link {\n    color: #01AAED\n}\n\n.laytable-cell-checkbox, .laytable-cell-numbers, .laytable-cell-radio, .laytable-cell-space {\n    padding: 0;\n    text-align: center\n}\n\n.layui-table-body {\n    position: relative;\n    overflow: auto;\n    margin-right: -1px;\n    margin-bottom: -1px\n}\n\n.layui-table-body .layui-none {\n    line-height: 26px;\n    padding: 15px;\n    text-align: center;\n    color: #999\n}\n\n.layui-table-fixed {\n    position: absolute;\n    left: 0;\n    top: 0;\n    z-index: 101\n}\n\n.layui-table-fixed .layui-table-body {\n    overflow: hidden\n}\n\n.layui-table-fixed-l {\n    box-shadow: 0 -1px 8px rgba(0, 0, 0, .08)\n}\n\n.layui-table-fixed-r {\n    left: auto;\n    right: -1px;\n    border-width: 0 0 0 1px;\n    box-shadow: -1px 0 8px rgba(0, 0, 0, .08)\n}\n\n.layui-table-fixed-r .layui-table-header {\n    position: relative;\n    overflow: visible\n}\n\n.layui-table-mend {\n    position: absolute;\n    right: -49px;\n    top: 0;\n    height: 100%;\n    width: 50px\n}\n\n.layui-table-tool {\n    position: relative;\n    z-index: 890;\n    width: 100%;\n    min-height: 50px;\n    line-height: 30px;\n    padding: 10px 15px;\n    border-width: 0 0 1px\n}\n\n.layui-table-tool .layui-btn-container {\n    margin-bottom: -10px\n}\n\n.layui-table-page, .layui-table-total {\n    border-width: 1px 0 0;\n    margin-bottom: -1px;\n    overflow: hidden\n}\n\n.layui-table-page {\n    position: relative;\n    width: 100%;\n    padding: 7px 7px 0;\n    height: 41px;\n    font-size: 12px;\n    white-space: nowrap\n}\n\n.layui-table-page > div {\n    height: 26px\n}\n\n.layui-table-page .layui-laypage {\n    margin: 0\n}\n\n.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span {\n    height: 26px;\n    line-height: 26px;\n    margin-bottom: 10px;\n    border: none;\n    background: 0 0\n}\n\n.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span.layui-laypage-curr {\n    padding: 0 12px\n}\n\n.layui-table-page .layui-laypage span {\n    margin-left: 0;\n    padding: 0\n}\n\n.layui-table-page .layui-laypage .layui-laypage-prev {\n    margin-left: -7px !important\n}\n\n.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em {\n    left: 0;\n    top: 0;\n    padding: 0\n}\n\n.layui-table-page .layui-laypage button, .layui-table-page .layui-laypage input {\n    height: 26px;\n    line-height: 26px\n}\n\n.layui-table-page .layui-laypage input {\n    width: 40px\n}\n\n.layui-table-page .layui-laypage button {\n    padding: 0 10px\n}\n\n.layui-table-page select {\n    height: 18px\n}\n\n.layui-table-patch .layui-table-cell {\n    padding: 0;\n    width: 30px\n}\n\n.layui-table-edit {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n    padding: 0 14px 1px;\n    border-radius: 0;\n    box-shadow: 1px 1px 20px rgba(0, 0, 0, .15)\n}\n\n.layui-table-edit:focus {\n    border-color: #5FB878 !important\n}\n\nselect.layui-table-edit {\n    padding: 0 0 0 10px;\n    border-color: #C9C9C9\n}\n\n.layui-table-view .layui-form-checkbox, .layui-table-view .layui-form-radio, .layui-table-view .layui-form-switch {\n    top: 0;\n    margin: 0;\n    box-sizing: content-box\n}\n\n.layui-table-view .layui-form-checkbox {\n    top: -1px;\n    height: 26px;\n    line-height: 26px\n}\n\n.layui-table-view .layui-form-checkbox i {\n    height: 26px\n}\n\n.layui-table-grid .layui-table-cell {\n    overflow: visible\n}\n\n.layui-table-grid-down {\n    position: absolute;\n    top: 0;\n    right: 0;\n    width: 26px;\n    height: 100%;\n    padding: 5px 0;\n    border-width: 0 0 0 1px;\n    text-align: center;\n    background-color: #fff;\n    color: #999;\n    cursor: pointer\n}\n\n.layui-table-grid-down .layui-icon {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    margin: -8px 0 0 -8px\n}\n\n.layui-table-grid-down:hover {\n    background-color: #fbfbfb\n}\n\nbody .layui-table-tips .layui-layer-content {\n    background: 0 0;\n    padding: 0;\n    box-shadow: 0 1px 6px rgba(0, 0, 0, .12)\n}\n\n.layui-table-tips-main {\n    margin: -44px 0 0 -1px;\n    max-height: 150px;\n    padding: 8px 15px;\n    font-size: 14px;\n    overflow-y: scroll;\n    background-color: #fff;\n    color: #666\n}\n\n.layui-table-tips-c {\n    position: absolute;\n    right: -3px;\n    top: -13px;\n    width: 20px;\n    height: 20px;\n    padding: 3px;\n    cursor: pointer;\n    background-color: #666;\n    border-radius: 50%;\n    color: #fff\n}\n\n.layui-table-tips-c:hover {\n    background-color: #777\n}\n\n.layui-table-tips-c:before {\n    position: relative;\n    right: -2px\n}\n\n.layui-upload-file {\n    display: none !important;\n    opacity: .01;\n    filter: Alpha(opacity=1)\n}\n\n.layui-upload-drag, .layui-upload-form, .layui-upload-wrap {\n    display: inline-block\n}\n\n.layui-upload-list {\n    margin: 10px 0\n}\n\n.layui-upload-choose {\n    padding: 0 10px;\n    color: #999\n}\n\n.layui-upload-drag {\n    position: relative;\n    padding: 30px;\n    border: 1px dashed #e2e2e2;\n    background-color: #fff;\n    text-align: center;\n    cursor: pointer;\n    color: #999\n}\n\n.layui-upload-drag .layui-icon {\n    font-size: 50px;\n    color: #009688\n}\n\n.layui-upload-drag[lay-over] {\n    border-color: #009688\n}\n\n.layui-upload-iframe {\n    position: absolute;\n    width: 0;\n    height: 0;\n    border: 0;\n    visibility: hidden\n}\n\n.layui-upload-wrap {\n    position: relative;\n    vertical-align: middle\n}\n\n.layui-upload-wrap .layui-upload-file {\n    display: block !important;\n    position: absolute;\n    left: 0;\n    top: 0;\n    z-index: 10;\n    font-size: 100px;\n    width: 100%;\n    height: 100%;\n    opacity: .01;\n    filter: Alpha(opacity=1);\n    cursor: pointer\n}\n\n.layui-transfer-active, .layui-transfer-box {\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-transfer-box, .layui-transfer-header, .layui-transfer-search {\n    border-width: 0;\n    border-style: solid;\n    border-color: #e6e6e6\n}\n\n.layui-transfer-box {\n    position: relative;\n    border-width: 1px;\n    width: 200px;\n    height: 360px;\n    border-radius: 2px;\n    background-color: #fff\n}\n\n.layui-transfer-box .layui-form-checkbox {\n    width: 100%;\n    margin: 0 !important\n}\n\n.layui-transfer-header {\n    height: 38px;\n    line-height: 38px;\n    padding: 0 10px;\n    border-bottom-width: 1px\n}\n\n.layui-transfer-search {\n    position: relative;\n    padding: 10px;\n    border-bottom-width: 1px\n}\n\n.layui-transfer-search .layui-input {\n    height: 32px;\n    padding-left: 30px;\n    font-size: 12px\n}\n\n.layui-transfer-search .layui-icon-search {\n    position: absolute;\n    left: 20px;\n    top: 50%;\n    margin-top: -8px;\n    color: #666\n}\n\n.layui-transfer-active {\n    margin: 0 15px\n}\n\n.layui-transfer-active .layui-btn {\n    display: block;\n    margin: 0;\n    padding: 0 15px;\n    background-color: #5FB878;\n    border-color: #5FB878;\n    color: #fff\n}\n\n.layui-transfer-active .layui-btn-disabled {\n    background-color: #FBFBFB;\n    border-color: #e6e6e6;\n    color: #C9C9C9\n}\n\n.layui-transfer-active .layui-btn:first-child {\n    margin-bottom: 15px\n}\n\n.layui-transfer-active .layui-btn .layui-icon {\n    margin: 0;\n    font-size: 14px !important\n}\n\n.layui-transfer-data {\n    padding: 5px 0;\n    overflow: auto\n}\n\n.layui-transfer-data li {\n    height: 32px;\n    line-height: 32px;\n    padding: 0 10px\n}\n\n.layui-transfer-data li:hover {\n    background-color: #f2f2f2;\n    transition: .5s all\n}\n\n.layui-transfer-data .layui-none {\n    padding: 15px 10px;\n    text-align: center;\n    color: #999\n}\n\n.layui-nav {\n    position: relative;\n    padding: 0 20px;\n    background-color: #393D49;\n    color: #fff;\n    border-radius: 2px;\n    font-size: 0;\n    box-sizing: border-box\n}\n\n.layui-nav * {\n    font-size: 14px\n}\n\n.layui-nav .layui-nav-item {\n    position: relative;\n    display: inline-block;\n    *display: inline;\n    *zoom: 1;\n    vertical-align: middle;\n    line-height: 60px\n}\n\n.layui-nav .layui-nav-item a {\n    display: block;\n    padding: 0 20px;\n    color: #fff;\n    color: rgba(255, 255, 255, .7);\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree .layui-nav-itemed:after {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 0;\n    height: 5px;\n    background-color: #5FB878;\n    transition: all .2s;\n    -webkit-transition: all .2s\n}\n\n.layui-nav-bar {\n    z-index: 1000\n}\n\n.layui-nav .layui-nav-item a:hover, .layui-nav .layui-this a {\n    color: #fff\n}\n\n.layui-nav .layui-this:after {\n    content: '';\n    top: auto;\n    bottom: 0;\n    width: 100%\n}\n\n.layui-nav-img {\n    width: 30px;\n    height: 30px;\n    margin-right: 10px;\n    border-radius: 50%\n}\n\n.layui-nav .layui-nav-more {\n    content: '';\n    width: 0;\n    height: 0;\n    border-style: solid dashed dashed;\n    border-color: #fff transparent transparent;\n    overflow: hidden;\n    cursor: pointer;\n    transition: all .2s;\n    -webkit-transition: all .2s;\n    position: absolute;\n    top: 50%;\n    right: 3px;\n    margin-top: -3px;\n    border-width: 6px;\n    border-top-color: rgba(255, 255, 255, .7)\n}\n\n.layui-nav .layui-nav-mored, .layui-nav-itemed > a .layui-nav-more {\n    margin-top: -9px;\n    border-style: dashed dashed solid;\n    border-color: transparent transparent #fff\n}\n\n.layui-nav-child {\n    display: none;\n    position: absolute;\n    left: 0;\n    top: 65px;\n    min-width: 100%;\n    line-height: 36px;\n    padding: 5px 0;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, .12);\n    border: 1px solid #d2d2d2;\n    background-color: #fff;\n    z-index: 100;\n    border-radius: 2px;\n    white-space: nowrap\n}\n\n.layui-nav .layui-nav-child a {\n    color: #333\n}\n\n.layui-nav .layui-nav-child a:hover {\n    background-color: #f2f2f2;\n    color: #000\n}\n\n.layui-nav-child dd {\n    position: relative\n}\n\n.layui-nav .layui-nav-child dd.layui-this a, .layui-nav-child dd.layui-this {\n    background-color: #5FB878;\n    color: #fff\n}\n\n.layui-nav-child dd.layui-this:after {\n    display: none\n}\n\n.layui-nav-tree {\n    width: 200px;\n    padding: 0\n}\n\n.layui-nav-tree .layui-nav-item {\n    display: block;\n    width: 100%;\n    line-height: 45px\n}\n\n.layui-nav-tree .layui-nav-item a {\n    position: relative;\n    height: 45px;\n    line-height: 45px;\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap\n}\n\n.layui-nav-tree .layui-nav-item a:hover {\n    background-color: #4E5465\n}\n\n.layui-nav-tree .layui-nav-bar {\n    width: 5px;\n    height: 0;\n    background-color: #009688\n}\n\n.layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-this, .layui-nav-tree .layui-this > a, .layui-nav-tree .layui-this > a:hover {\n    background-color: #009688;\n    color: #fff\n}\n\n.layui-nav-tree .layui-this:after {\n    display: none\n}\n\n.layui-nav-itemed > a, .layui-nav-tree .layui-nav-title a, .layui-nav-tree .layui-nav-title a:hover {\n    color: #fff !important\n}\n\n.layui-nav-tree .layui-nav-child {\n    position: relative;\n    z-index: 0;\n    top: 0;\n    border: none;\n    box-shadow: none\n}\n\n.layui-nav-tree .layui-nav-child a {\n    height: 40px;\n    line-height: 40px;\n    color: #fff;\n    color: rgba(255, 255, 255, .7)\n}\n\n.layui-nav-tree .layui-nav-child, .layui-nav-tree .layui-nav-child a:hover {\n    background: 0 0;\n    color: #fff\n}\n\n.layui-nav-tree .layui-nav-more {\n    right: 10px\n}\n\n.layui-nav-itemed > .layui-nav-child {\n    display: block;\n    padding: 0;\n    background-color: rgba(0, 0, 0, .3) !important\n}\n\n.layui-nav-itemed > .layui-nav-child > .layui-this > .layui-nav-child {\n    display: block\n}\n\n.layui-nav-side {\n    position: fixed;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    overflow-x: hidden;\n    z-index: 999\n}\n\n.layui-bg-blue .layui-nav-bar, .layui-bg-blue .layui-nav-itemed:after, .layui-bg-blue .layui-this:after {\n    background-color: #93D1FF\n}\n\n.layui-bg-blue .layui-nav-child dd.layui-this {\n    background-color: #1E9FFF\n}\n\n.layui-bg-blue .layui-nav-itemed > a, .layui-nav-tree.layui-bg-blue .layui-nav-title a, .layui-nav-tree.layui-bg-blue .layui-nav-title a:hover {\n    background-color: #007DDB !important\n}\n\n.layui-breadcrumb {\n    font-size: 0\n}\n\n.layui-breadcrumb > * {\n    font-size: 14px\n}\n\n.layui-breadcrumb a {\n    color: #999 !important\n}\n\n.layui-breadcrumb a:hover {\n    color: #5FB878 !important\n}\n\n.layui-breadcrumb a cite {\n    color: #666;\n    font-style: normal\n}\n\n.layui-breadcrumb span[lay-separator] {\n    margin: 0 10px;\n    color: #999\n}\n\n.layui-tab {\n    margin: 10px 0;\n    text-align: left !important\n}\n\n.layui-tab[overflow] > .layui-tab-title {\n    overflow: hidden\n}\n\n.layui-tab-title {\n    position: relative;\n    left: 0;\n    height: 40px;\n    white-space: nowrap;\n    font-size: 0;\n    border-bottom-width: 1px;\n    border-bottom-style: solid;\n    transition: all .2s;\n    -webkit-transition: all .2s\n}\n\n.layui-tab-title li {\n    display: inline-block;\n    *display: inline;\n    *zoom: 1;\n    vertical-align: middle;\n    font-size: 14px;\n    transition: all .2s;\n    -webkit-transition: all .2s;\n    position: relative;\n    line-height: 40px;\n    min-width: 65px;\n    padding: 0 15px;\n    text-align: center;\n    cursor: pointer\n}\n\n.layui-tab-title li a {\n    display: block\n}\n\n.layui-tab-title .layui-this {\n    color: #000\n}\n\n.layui-tab-title .layui-this:after {\n    position: absolute;\n    left: 0;\n    top: 0;\n    content: '';\n    width: 100%;\n    height: 41px;\n    border-width: 1px;\n    border-style: solid;\n    border-bottom-color: #fff;\n    border-radius: 2px 2px 0 0;\n    box-sizing: border-box;\n    pointer-events: none\n}\n\n.layui-tab-bar {\n    position: absolute;\n    right: 0;\n    top: 0;\n    z-index: 10;\n    width: 30px;\n    height: 39px;\n    line-height: 39px;\n    border-width: 1px;\n    border-style: solid;\n    border-radius: 2px;\n    text-align: center;\n    background-color: #fff;\n    cursor: pointer\n}\n\n.layui-tab-bar .layui-icon {\n    position: relative;\n    display: inline-block;\n    top: 3px;\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-tab-item {\n    display: none\n}\n\n.layui-tab-more {\n    padding-right: 30px;\n    height: auto !important;\n    white-space: normal !important\n}\n\n.layui-tab-more li.layui-this:after {\n    border-bottom-color: #e2e2e2;\n    border-radius: 2px\n}\n\n.layui-tab-more .layui-tab-bar .layui-icon {\n    top: -2px;\n    top: 3px \\9;\n    -webkit-transform: rotate(180deg);\n    transform: rotate(180deg)\n}\n\n:root .layui-tab-more .layui-tab-bar .layui-icon {\n    top: -2px \\0/ IE9\n}\n\n.layui-tab-content {\n    padding: 10px\n}\n\n.layui-tab-title li .layui-tab-close {\n    position: relative;\n    display: inline-block;\n    width: 18px;\n    height: 18px;\n    line-height: 20px;\n    margin-left: 8px;\n    top: 1px;\n    text-align: center;\n    font-size: 14px;\n    color: #c2c2c2;\n    transition: all .2s;\n    -webkit-transition: all .2s\n}\n\n.layui-tab-title li .layui-tab-close:hover {\n    border-radius: 2px;\n    background-color: #FF5722;\n    color: #fff\n}\n\n.layui-tab-brief > .layui-tab-title .layui-this {\n    color: #009688\n}\n\n.layui-tab-brief > .layui-tab-more li.layui-this:after, .layui-tab-brief > .layui-tab-title .layui-this:after {\n    border: none;\n    border-radius: 0;\n    border-bottom: 2px solid #5FB878\n}\n\n.layui-tab-brief[overflow] > .layui-tab-title .layui-this:after {\n    top: -1px\n}\n\n.layui-tab-card {\n    border-width: 1px;\n    border-style: solid;\n    border-radius: 2px;\n    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1)\n}\n\n.layui-tab-card > .layui-tab-title {\n    background-color: #f2f2f2\n}\n\n.layui-tab-card > .layui-tab-title li {\n    margin-right: -1px;\n    margin-left: -1px\n}\n\n.layui-tab-card > .layui-tab-title .layui-this {\n    background-color: #fff\n}\n\n.layui-tab-card > .layui-tab-title .layui-this:after {\n    border-top: none;\n    border-width: 1px;\n    border-bottom-color: #fff\n}\n\n.layui-tab-card > .layui-tab-title .layui-tab-bar {\n    height: 40px;\n    line-height: 40px;\n    border-radius: 0;\n    border-top: none;\n    border-right: none\n}\n\n.layui-tab-card > .layui-tab-more .layui-this {\n    background: 0 0;\n    color: #5FB878\n}\n\n.layui-tab-card > .layui-tab-more .layui-this:after {\n    border: none\n}\n\n.layui-timeline {\n    padding-left: 5px\n}\n\n.layui-timeline-item {\n    position: relative;\n    padding-bottom: 20px\n}\n\n.layui-timeline-axis {\n    position: absolute;\n    left: -5px;\n    top: 0;\n    z-index: 10;\n    width: 20px;\n    height: 20px;\n    line-height: 20px;\n    background-color: #fff;\n    color: #5FB878;\n    border-radius: 50%;\n    text-align: center;\n    cursor: pointer\n}\n\n.layui-timeline-axis:hover {\n    color: #FF5722\n}\n\n.layui-timeline-item:before {\n    content: '';\n    position: absolute;\n    left: 5px;\n    top: 0;\n    z-index: 0;\n    width: 1px;\n    height: 100%\n}\n\n.layui-timeline-item:last-child:before {\n    display: none\n}\n\n.layui-timeline-item:first-child:before {\n    display: block\n}\n\n.layui-timeline-content {\n    padding-left: 25px\n}\n\n.layui-timeline-title {\n    position: relative;\n    margin-bottom: 10px\n}\n\n.layui-badge, .layui-badge-dot, .layui-badge-rim {\n    position: relative;\n    display: inline-block;\n    padding: 0 6px;\n    font-size: 12px;\n    text-align: center;\n    background-color: #FF5722;\n    color: #fff;\n    border-radius: 2px\n}\n\n.layui-badge {\n    height: 18px;\n    line-height: 18px\n}\n\n.layui-badge-dot {\n    width: 8px;\n    height: 8px;\n    padding: 0;\n    border-radius: 50%\n}\n\n.layui-badge-rim {\n    height: 18px;\n    line-height: 18px;\n    border-width: 1px;\n    border-style: solid;\n    background-color: #fff;\n    color: #666\n}\n\n.layui-btn .layui-badge, .layui-btn .layui-badge-dot {\n    margin-left: 5px\n}\n\n.layui-nav .layui-badge, .layui-nav .layui-badge-dot {\n    position: absolute;\n    top: 50%;\n    margin: -8px 6px 0\n}\n\n.layui-tab-title .layui-badge, .layui-tab-title .layui-badge-dot {\n    left: 5px;\n    top: -2px\n}\n\n.layui-carousel {\n    position: relative;\n    left: 0;\n    top: 0;\n    background-color: #f8f8f8\n}\n\n.layui-carousel > [carousel-item] {\n    position: relative;\n    width: 100%;\n    height: 100%;\n    overflow: hidden\n}\n\n.layui-carousel > [carousel-item]:before {\n    position: absolute;\n    content: '\\e63d';\n    left: 50%;\n    top: 50%;\n    width: 100px;\n    line-height: 20px;\n    margin: -10px 0 0 -50px;\n    text-align: center;\n    color: #c2c2c2;\n    font-family: layui-icon !important;\n    font-size: 30px;\n    font-style: normal;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale\n}\n\n.layui-carousel > [carousel-item] > * {\n    display: none;\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n    background-color: #f8f8f8;\n    transition-duration: .3s;\n    -webkit-transition-duration: .3s\n}\n\n.layui-carousel-updown > * {\n    -webkit-transition: .3s ease-in-out up;\n    transition: .3s ease-in-out up\n}\n\n.layui-carousel-arrow {\n    display: none \\9;\n    opacity: 0;\n    position: absolute;\n    left: 10px;\n    top: 50%;\n    margin-top: -18px;\n    width: 36px;\n    height: 36px;\n    line-height: 36px;\n    text-align: center;\n    font-size: 20px;\n    border: 0;\n    border-radius: 50%;\n    background-color: rgba(0, 0, 0, .2);\n    color: #fff;\n    -webkit-transition-duration: .3s;\n    transition-duration: .3s;\n    cursor: pointer\n}\n\n.layui-carousel-arrow[lay-type=add] {\n    left: auto !important;\n    right: 10px\n}\n\n.layui-carousel:hover .layui-carousel-arrow[lay-type=add], .layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add] {\n    right: 20px\n}\n\n.layui-carousel[lay-arrow=always] .layui-carousel-arrow {\n    opacity: 1;\n    left: 20px\n}\n\n.layui-carousel[lay-arrow=none] .layui-carousel-arrow {\n    display: none\n}\n\n.layui-carousel-arrow:hover, .layui-carousel-ind ul:hover {\n    background-color: rgba(0, 0, 0, .35)\n}\n\n.layui-carousel:hover .layui-carousel-arrow {\n    display: block \\9;\n    opacity: 1;\n    left: 20px\n}\n\n.layui-carousel-ind {\n    position: relative;\n    top: -35px;\n    width: 100%;\n    line-height: 0 !important;\n    text-align: center;\n    font-size: 0\n}\n\n.layui-carousel[lay-indicator=outside] {\n    margin-bottom: 30px\n}\n\n.layui-carousel[lay-indicator=outside] .layui-carousel-ind {\n    top: 10px\n}\n\n.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul {\n    background-color: rgba(0, 0, 0, .5)\n}\n\n.layui-carousel[lay-indicator=none] .layui-carousel-ind {\n    display: none\n}\n\n.layui-carousel-ind ul {\n    display: inline-block;\n    padding: 5px;\n    background-color: rgba(0, 0, 0, .2);\n    border-radius: 10px;\n    -webkit-transition-duration: .3s;\n    transition-duration: .3s\n}\n\n.layui-carousel-ind li {\n    display: inline-block;\n    width: 10px;\n    height: 10px;\n    margin: 0 3px;\n    font-size: 14px;\n    background-color: #e2e2e2;\n    background-color: rgba(255, 255, 255, .5);\n    border-radius: 50%;\n    cursor: pointer;\n    -webkit-transition-duration: .3s;\n    transition-duration: .3s\n}\n\n.layui-carousel-ind li:hover {\n    background-color: rgba(255, 255, 255, .7)\n}\n\n.layui-carousel-ind li.layui-this {\n    background-color: #fff\n}\n\n.layui-carousel > [carousel-item] > .layui-carousel-next, .layui-carousel > [carousel-item] > .layui-carousel-prev, .layui-carousel > [carousel-item] > .layui-this {\n    display: block\n}\n\n.layui-carousel > [carousel-item] > .layui-this {\n    left: 0\n}\n\n.layui-carousel > [carousel-item] > .layui-carousel-prev {\n    left: -100%\n}\n\n.layui-carousel > [carousel-item] > .layui-carousel-next {\n    left: 100%\n}\n\n.layui-carousel > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel > [carousel-item] > .layui-carousel-prev.layui-carousel-right {\n    left: 0\n}\n\n.layui-carousel > [carousel-item] > .layui-this.layui-carousel-left {\n    left: -100%\n}\n\n.layui-carousel > [carousel-item] > .layui-this.layui-carousel-right {\n    left: 100%\n}\n\n.layui-carousel[lay-anim=updown] .layui-carousel-arrow {\n    left: 50% !important;\n    top: 20px;\n    margin: 0 0 0 -18px\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > *, .layui-carousel[lay-anim=fade] > [carousel-item] > * {\n    left: 0 !important\n}\n\n.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add] {\n    top: auto !important;\n    bottom: 20px\n}\n\n.layui-carousel[lay-anim=updown] .layui-carousel-ind {\n    position: absolute;\n    top: 50%;\n    right: 20px;\n    width: auto;\n    height: auto\n}\n\n.layui-carousel[lay-anim=updown] .layui-carousel-ind ul {\n    padding: 3px 5px\n}\n\n.layui-carousel[lay-anim=updown] .layui-carousel-ind li {\n    display: block;\n    margin: 6px 0\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this {\n    top: 0\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev {\n    top: -100%\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next {\n    top: 100%\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev.layui-carousel-right {\n    top: 0\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-left {\n    top: -100%\n}\n\n.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-right {\n    top: 100%\n}\n\n.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev {\n    opacity: 0\n}\n\n.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev.layui-carousel-right {\n    opacity: 1\n}\n\n.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-right {\n    opacity: 0\n}\n\n.layui-fixbar {\n    position: fixed;\n    right: 15px;\n    bottom: 15px;\n    z-index: 999999\n}\n\n.layui-fixbar li {\n    width: 50px;\n    height: 50px;\n    line-height: 50px;\n    margin-bottom: 1px;\n    text-align: center;\n    cursor: pointer;\n    font-size: 30px;\n    background-color: #9F9F9F;\n    color: #fff;\n    border-radius: 2px;\n    opacity: .95\n}\n\n.layui-fixbar li:hover {\n    opacity: .85\n}\n\n.layui-fixbar li:active {\n    opacity: 1\n}\n\n.layui-fixbar .layui-fixbar-top {\n    display: none;\n    font-size: 40px\n}\n\nbody .layui-util-face {\n    border: none;\n    background: 0 0\n}\n\nbody .layui-util-face .layui-layer-content {\n    padding: 0;\n    background-color: #fff;\n    color: #666;\n    box-shadow: none\n}\n\n.layui-util-face .layui-layer-TipsG {\n    display: none\n}\n\n.layui-util-face ul {\n    position: relative;\n    width: 372px;\n    padding: 10px;\n    border: 1px solid #D9D9D9;\n    background-color: #fff;\n    box-shadow: 0 0 20px rgba(0, 0, 0, .2)\n}\n\n.layui-util-face ul li {\n    cursor: pointer;\n    float: left;\n    border: 1px solid #e8e8e8;\n    height: 22px;\n    width: 26px;\n    overflow: hidden;\n    margin: -1px 0 0 -1px;\n    padding: 4px 2px;\n    text-align: center\n}\n\n.layui-util-face ul li:hover {\n    position: relative;\n    z-index: 2;\n    border: 1px solid #eb7350;\n    background: #fff9ec\n}\n\n.layui-code {\n    position: relative;\n    margin: 10px 0;\n    padding: 15px;\n    line-height: 20px;\n    border: 1px solid #ddd;\n    border-left-width: 6px;\n    background-color: #F2F2F2;\n    color: #333;\n    font-family: Courier New;\n    font-size: 12px\n}\n\n.layui-rate, .layui-rate * {\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-rate {\n    padding: 10px 5px 10px 0;\n    font-size: 0\n}\n\n.layui-rate li i.layui-icon {\n    font-size: 20px;\n    color: #FFB800;\n    margin-right: 5px;\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-rate li i:hover {\n    cursor: pointer;\n    transform: scale(1.12);\n    -webkit-transform: scale(1.12)\n}\n\n.layui-rate[readonly] li i:hover {\n    cursor: default;\n    transform: scale(1)\n}\n\n.layui-colorpicker {\n    width: 26px;\n    height: 26px;\n    border: 1px solid #e6e6e6;\n    padding: 5px;\n    border-radius: 2px;\n    line-height: 24px;\n    display: inline-block;\n    cursor: pointer;\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n.layui-colorpicker:hover {\n    border-color: #d2d2d2\n}\n\n.layui-colorpicker.layui-colorpicker-lg {\n    width: 34px;\n    height: 34px;\n    line-height: 32px\n}\n\n.layui-colorpicker.layui-colorpicker-sm {\n    width: 24px;\n    height: 24px;\n    line-height: 22px\n}\n\n.layui-colorpicker.layui-colorpicker-xs {\n    width: 22px;\n    height: 22px;\n    line-height: 20px\n}\n\n.layui-colorpicker-trigger-bgcolor {\n    display: block;\n    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);\n    border-radius: 2px\n}\n\n.layui-colorpicker-trigger-span {\n    display: block;\n    height: 100%;\n    box-sizing: border-box;\n    border: 1px solid rgba(0, 0, 0, .15);\n    border-radius: 2px;\n    text-align: center\n}\n\n.layui-colorpicker-trigger-i {\n    display: inline-block;\n    color: #FFF;\n    font-size: 12px\n}\n\n.layui-colorpicker-trigger-i.layui-icon-close {\n    color: #999\n}\n\n.layui-colorpicker-main {\n    position: absolute;\n    z-index: 66666666;\n    width: 280px;\n    padding: 7px;\n    background: #FFF;\n    border: 1px solid #d2d2d2;\n    border-radius: 2px;\n    box-shadow: 0 2px 4px rgba(0, 0, 0, .12)\n}\n\n.layui-colorpicker-main-wrapper {\n    height: 180px;\n    position: relative\n}\n\n.layui-colorpicker-basis {\n    width: 260px;\n    height: 100%;\n    position: relative\n}\n\n.layui-colorpicker-basis-white {\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    top: 0;\n    left: 0;\n    background: linear-gradient(90deg, #FFF, hsla(0, 0%, 100%, 0))\n}\n\n.layui-colorpicker-basis-black {\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    top: 0;\n    left: 0;\n    background: linear-gradient(0deg, #000, transparent)\n}\n\n.layui-colorpicker-basis-cursor {\n    width: 10px;\n    height: 10px;\n    border: 1px solid #FFF;\n    border-radius: 50%;\n    position: absolute;\n    top: -3px;\n    right: -3px;\n    cursor: pointer\n}\n\n.layui-colorpicker-side {\n    position: absolute;\n    top: 0;\n    right: 0;\n    width: 12px;\n    height: 100%;\n    background: linear-gradient(red, #FF0, #0F0, #0FF, #00F, #F0F, red)\n}\n\n.layui-colorpicker-side-slider {\n    width: 100%;\n    height: 5px;\n    box-shadow: 0 0 1px #888;\n    box-sizing: border-box;\n    background: #FFF;\n    border-radius: 1px;\n    border: 1px solid #f0f0f0;\n    cursor: pointer;\n    position: absolute;\n    left: 0\n}\n\n.layui-colorpicker-main-alpha {\n    display: none;\n    height: 12px;\n    margin-top: 7px;\n    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)\n}\n\n.layui-colorpicker-alpha-bgcolor {\n    height: 100%;\n    position: relative\n}\n\n.layui-colorpicker-alpha-slider {\n    width: 5px;\n    height: 100%;\n    box-shadow: 0 0 1px #888;\n    box-sizing: border-box;\n    background: #FFF;\n    border-radius: 1px;\n    border: 1px solid #f0f0f0;\n    cursor: pointer;\n    position: absolute;\n    top: 0\n}\n\n.layui-colorpicker-main-pre {\n    padding-top: 7px;\n    font-size: 0\n}\n\n.layui-colorpicker-pre {\n    width: 20px;\n    height: 20px;\n    border-radius: 2px;\n    display: inline-block;\n    margin-left: 6px;\n    margin-bottom: 7px;\n    cursor: pointer\n}\n\n.layui-colorpicker-pre:nth-child(11n+1) {\n    margin-left: 0\n}\n\n.layui-colorpicker-pre-isalpha {\n    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)\n}\n\n.layui-colorpicker-pre.layui-this {\n    box-shadow: 0 0 3px 2px rgba(0, 0, 0, .15)\n}\n\n.layui-colorpicker-pre > div {\n    height: 100%;\n    border-radius: 2px\n}\n\n.layui-colorpicker-main-input {\n    text-align: right;\n    padding-top: 7px\n}\n\n.layui-colorpicker-main-input .layui-btn-container .layui-btn {\n    margin: 0 0 0 10px\n}\n\n.layui-colorpicker-main-input div.layui-inline {\n    float: left;\n    margin-right: 10px;\n    font-size: 14px\n}\n\n.layui-colorpicker-main-input input.layui-input {\n    width: 150px;\n    height: 30px;\n    color: #666\n}\n\n.layui-slider {\n    height: 4px;\n    background: #e2e2e2;\n    border-radius: 3px;\n    position: relative;\n    cursor: pointer\n}\n\n.layui-slider-bar {\n    border-radius: 3px;\n    position: absolute;\n    height: 100%\n}\n\n.layui-slider-step {\n    position: absolute;\n    top: 0;\n    width: 4px;\n    height: 4px;\n    border-radius: 50%;\n    background: #FFF;\n    -webkit-transform: translateX(-50%);\n    transform: translateX(-50%)\n}\n\n.layui-slider-wrap {\n    width: 36px;\n    height: 36px;\n    position: absolute;\n    top: -16px;\n    -webkit-transform: translateX(-50%);\n    transform: translateX(-50%);\n    z-index: 10;\n    text-align: center\n}\n\n.layui-slider-wrap-btn {\n    width: 12px;\n    height: 12px;\n    border-radius: 50%;\n    background: #FFF;\n    display: inline-block;\n    vertical-align: middle;\n    cursor: pointer;\n    transition: .3s\n}\n\n.layui-slider-wrap:after {\n    content: \"\";\n    height: 100%;\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-slider-wrap-btn.layui-slider-hover, .layui-slider-wrap-btn:hover {\n    transform: scale(1.2)\n}\n\n.layui-slider-wrap-btn.layui-disabled:hover {\n    transform: scale(1) !important\n}\n\n.layui-slider-tips {\n    position: absolute;\n    top: -42px;\n    z-index: 66666666;\n    white-space: nowrap;\n    display: none;\n    -webkit-transform: translateX(-50%);\n    transform: translateX(-50%);\n    color: #FFF;\n    background: #000;\n    border-radius: 3px;\n    height: 25px;\n    line-height: 25px;\n    padding: 0 10px\n}\n\n.layui-slider-tips:after {\n    content: '';\n    position: absolute;\n    bottom: -12px;\n    left: 50%;\n    margin-left: -6px;\n    width: 0;\n    height: 0;\n    border-width: 6px;\n    border-style: solid;\n    border-color: #000 transparent transparent\n}\n\n.layui-slider-input {\n    width: 70px;\n    height: 32px;\n    border: 1px solid #e6e6e6;\n    border-radius: 3px;\n    font-size: 16px;\n    line-height: 32px;\n    position: absolute;\n    right: 0;\n    top: -15px\n}\n\n.layui-slider-input-btn {\n    display: none;\n    position: absolute;\n    top: 0;\n    right: 0;\n    width: 20px;\n    height: 100%;\n    border-left: 1px solid #d2d2d2\n}\n\n.layui-slider-input-btn i {\n    cursor: pointer;\n    position: absolute;\n    right: 0;\n    bottom: 0;\n    width: 20px;\n    height: 50%;\n    font-size: 12px;\n    line-height: 16px;\n    text-align: center;\n    color: #999\n}\n\n.layui-slider-input-btn i:first-child {\n    top: 0;\n    border-bottom: 1px solid #d2d2d2\n}\n\n.layui-slider-input-txt {\n    height: 100%;\n    font-size: 14px\n}\n\n.layui-slider-input-txt input {\n    height: 100%;\n    border: none\n}\n\n.layui-slider-input-btn i:hover {\n    color: #009688\n}\n\n.layui-slider-vertical {\n    width: 4px;\n    margin-left: 34px\n}\n\n.layui-slider-vertical .layui-slider-bar {\n    width: 4px\n}\n\n.layui-slider-vertical .layui-slider-step {\n    top: auto;\n    left: 0;\n    -webkit-transform: translateY(50%);\n    transform: translateY(50%)\n}\n\n.layui-slider-vertical .layui-slider-wrap {\n    top: auto;\n    left: -16px;\n    -webkit-transform: translateY(50%);\n    transform: translateY(50%)\n}\n\n.layui-slider-vertical .layui-slider-tips {\n    top: auto;\n    left: 2px\n}\n\n@media \\0screen {\n    .layui-slider-wrap-btn {\n        margin-left: -20px\n    }\n\n    .layui-slider-vertical .layui-slider-wrap-btn {\n        margin-left: 0;\n        margin-bottom: -20px\n    }\n\n    .layui-slider-vertical .layui-slider-tips {\n        margin-left: -8px\n    }\n\n    .layui-slider > span {\n        margin-left: 8px\n    }\n}\n\n.layui-tree {\n    line-height: 22px\n}\n\n.layui-tree .layui-form-checkbox {\n    margin: 0 !important\n}\n\n.layui-tree-set {\n    width: 100%;\n    position: relative\n}\n\n.layui-tree-pack {\n    display: none;\n    padding-left: 20px;\n    position: relative\n}\n\n.layui-tree-iconClick, .layui-tree-main {\n    display: inline-block;\n    vertical-align: middle\n}\n\n.layui-tree-line .layui-tree-pack {\n    padding-left: 27px\n}\n\n.layui-tree-line .layui-tree-set .layui-tree-set:after {\n    content: '';\n    position: absolute;\n    top: 14px;\n    left: -9px;\n    width: 17px;\n    height: 0;\n    border-top: 1px dotted #c0c4cc\n}\n\n.layui-tree-entry {\n    position: relative;\n    padding: 3px 0;\n    height: 20px;\n    white-space: nowrap\n}\n\n.layui-tree-entry:hover {\n    background-color: #eee\n}\n\n.layui-tree-line .layui-tree-entry:hover {\n    background-color: rgba(0, 0, 0, 0)\n}\n\n.layui-tree-line .layui-tree-entry:hover .layui-tree-txt {\n    color: #999;\n    text-decoration: underline;\n    transition: .3s\n}\n\n.layui-tree-main {\n    cursor: pointer;\n    padding-right: 10px\n}\n\n.layui-tree-line .layui-tree-set:before {\n    content: '';\n    position: absolute;\n    top: 0;\n    left: -9px;\n    width: 0;\n    height: 100%;\n    border-left: 1px dotted #c0c4cc\n}\n\n.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before {\n    height: 13px\n}\n\n.layui-tree-line .layui-tree-set.layui-tree-setHide:before {\n    height: 0\n}\n\n.layui-tree-iconClick {\n    position: relative;\n    height: 20px;\n    line-height: 20px;\n    margin: 0 10px;\n    color: #c0c4cc\n}\n\n.layui-tree-icon {\n    height: 12px;\n    line-height: 12px;\n    width: 12px;\n    text-align: center;\n    border: 1px solid #c0c4cc\n}\n\n.layui-tree-iconClick .layui-icon {\n    font-size: 18px\n}\n\n.layui-tree-icon .layui-icon {\n    font-size: 12px;\n    color: #666\n}\n\n.layui-tree-iconArrow {\n    padding: 0 5px\n}\n\n.layui-tree-iconArrow:after {\n    content: '';\n    position: absolute;\n    left: 4px;\n    top: 3px;\n    z-index: 100;\n    width: 0;\n    height: 0;\n    border-width: 5px;\n    border-style: solid;\n    border-color: transparent transparent transparent #c0c4cc;\n    transition: .5s\n}\n\n.layui-tree-btnGroup, .layui-tree-editInput {\n    position: relative;\n    vertical-align: middle;\n    display: inline-block\n}\n\n.layui-tree-spread > .layui-tree-entry > .layui-tree-iconClick > .layui-tree-iconArrow:after {\n    transform: rotate(90deg) translate(3px, 4px)\n}\n\n.layui-tree-txt {\n    display: inline-block;\n    vertical-align: middle;\n    color: #555\n}\n\n.layui-tree-search {\n    margin-bottom: 15px;\n    color: #666\n}\n\n.layui-tree-btnGroup .layui-icon {\n    display: inline-block;\n    vertical-align: middle;\n    padding: 0 2px;\n    cursor: pointer\n}\n\n.layui-tree-btnGroup .layui-icon:hover {\n    color: #999;\n    transition: .3s\n}\n\n.layui-tree-entry:hover .layui-tree-btnGroup {\n    visibility: visible\n}\n\n.layui-tree-editInput {\n    height: 20px;\n    line-height: 20px;\n    padding: 0 3px;\n    border: none;\n    background-color: rgba(0, 0, 0, .05)\n}\n\n.layui-tree-emptyText {\n    text-align: center;\n    color: #999\n}\n\n.layui-anim {\n    -webkit-animation-duration: .3s;\n    animation-duration: .3s;\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both\n}\n\n.layui-anim.layui-icon {\n    display: inline-block\n}\n\n.layui-anim-loop {\n    -webkit-animation-iteration-count: infinite;\n    animation-iteration-count: infinite\n}\n\n.layui-trans, .layui-trans a {\n    transition: all .3s;\n    -webkit-transition: all .3s\n}\n\n@-webkit-keyframes layui-rotate {\n    from {\n        -webkit-transform: rotate(0)\n    }\n    to {\n        -webkit-transform: rotate(360deg)\n    }\n}\n\n@keyframes layui-rotate {\n    from {\n        transform: rotate(0)\n    }\n    to {\n        transform: rotate(360deg)\n    }\n}\n\n.layui-anim-rotate {\n    -webkit-animation-name: layui-rotate;\n    animation-name: layui-rotate;\n    -webkit-animation-duration: 1s;\n    animation-duration: 1s;\n    -webkit-animation-timing-function: linear;\n    animation-timing-function: linear\n}\n\n@-webkit-keyframes layui-up {\n    from {\n        -webkit-transform: translate3d(0, 100%, 0);\n        opacity: .3\n    }\n    to {\n        -webkit-transform: translate3d(0, 0, 0);\n        opacity: 1\n    }\n}\n\n@keyframes layui-up {\n    from {\n        transform: translate3d(0, 100%, 0);\n        opacity: .3\n    }\n    to {\n        transform: translate3d(0, 0, 0);\n        opacity: 1\n    }\n}\n\n.layui-anim-up {\n    -webkit-animation-name: layui-up;\n    animation-name: layui-up\n}\n\n@-webkit-keyframes layui-upbit {\n    from {\n        -webkit-transform: translate3d(0, 30px, 0);\n        opacity: .3\n    }\n    to {\n        -webkit-transform: translate3d(0, 0, 0);\n        opacity: 1\n    }\n}\n\n@keyframes layui-upbit {\n    from {\n        transform: translate3d(0, 30px, 0);\n        opacity: .3\n    }\n    to {\n        transform: translate3d(0, 0, 0);\n        opacity: 1\n    }\n}\n\n.layui-anim-upbit {\n    -webkit-animation-name: layui-upbit;\n    animation-name: layui-upbit\n}\n\n@-webkit-keyframes layui-scale {\n    0% {\n        opacity: .3;\n        -webkit-transform: scale(.5)\n    }\n    100% {\n        opacity: 1;\n        -webkit-transform: scale(1)\n    }\n}\n\n@keyframes layui-scale {\n    0% {\n        opacity: .3;\n        -ms-transform: scale(.5);\n        transform: scale(.5)\n    }\n    100% {\n        opacity: 1;\n        -ms-transform: scale(1);\n        transform: scale(1)\n    }\n}\n\n.layui-anim-scale {\n    -webkit-animation-name: layui-scale;\n    animation-name: layui-scale\n}\n\n@-webkit-keyframes layui-scale-spring {\n    0% {\n        opacity: .5;\n        -webkit-transform: scale(.5)\n    }\n    80% {\n        opacity: .8;\n        -webkit-transform: scale(1.1)\n    }\n    100% {\n        opacity: 1;\n        -webkit-transform: scale(1)\n    }\n}\n\n@keyframes layui-scale-spring {\n    0% {\n        opacity: .5;\n        transform: scale(.5)\n    }\n    80% {\n        opacity: .8;\n        transform: scale(1.1)\n    }\n    100% {\n        opacity: 1;\n        transform: scale(1)\n    }\n}\n\n.layui-anim-scaleSpring {\n    -webkit-animation-name: layui-scale-spring;\n    animation-name: layui-scale-spring\n}\n\n@-webkit-keyframes layui-fadein {\n    0% {\n        opacity: 0\n    }\n    100% {\n        opacity: 1\n    }\n}\n\n@keyframes layui-fadein {\n    0% {\n        opacity: 0\n    }\n    100% {\n        opacity: 1\n    }\n}\n\n.layui-anim-fadein {\n    -webkit-animation-name: layui-fadein;\n    animation-name: layui-fadein\n}\n\n@-webkit-keyframes layui-fadeout {\n    0% {\n        opacity: 1\n    }\n    100% {\n        opacity: 0\n    }\n}\n\n@keyframes layui-fadeout {\n    0% {\n        opacity: 1\n    }\n    100% {\n        opacity: 0\n    }\n}\n\n.layui-anim-fadeout {\n    -webkit-animation-name: layui-fadeout;\n    animation-name: layui-fadeout\n}"
  },
  {
    "path": "src/main/webapp/static/layui/css/layui.mobile.css",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,legend,li,ol,p,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}html{font:12px 'Helvetica Neue','PingFang SC',STHeitiSC-Light,Helvetica,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0)}a{text-decoration:none;background:0 0}a:active,a:hover{outline:0}table{border-collapse:collapse;border-spacing:0}li{list-style:none}b,strong{font-weight:700}h1,h2,h3,h4,h5,h6{font-weight:500}address,cite,dfn,em,var{font-style:normal}dfn{font-style:italic}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}img{border:0;vertical-align:bottom}.layui-inline,input,label{vertical-align:middle}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;outline:0}button,select{text-transform:none}select{-webkit-appearance:none;border:none}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}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}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=1.0.7);src:url(../font/iconfont.eot?v=1.0.7#iefix) format('embedded-opentype'),url(../font/iconfont.woff?v=1.0.7) format('woff'),url(../font/iconfont.ttf?v=1.0.7) format('truetype'),url(../font/iconfont.svg?v=1.0.7#iconfont) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-box,.layui-box *{-webkit-box-sizing:content-box!important;-moz-box-sizing:content-box!important;box-sizing:content-box!important}.layui-border-box,.layui-border-box *{-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1}.layui-edge,.layui-upload-iframe{position:absolute;width:0;height:0}.layui-edge{border-style:dashed;border-color:transparent;overflow:hidden}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:active{background-color:#d2d2d2!important;color:#fff!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-upload-iframe{border:0;visibility:hidden}.layui-upload-enter{border:1px solid #009E94;background-color:#009E94;color:#fff;-webkit-transform:scale(1.1);transform:scale(1.1)}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}@-webkit-keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-left{-webkit-animation-name:layui-m-anim-left;animation-name:layui-m-anim-left}@-webkit-keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-right{-webkit-animation-name:layui-m-anim-right;animation-name:layui-m-anim-right}@-webkit-keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.layui-m-anim-lout{-webkit-animation-name:layui-m-anim-lout;animation-name:layui-m-anim-lout}@-webkit-keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}.layui-m-anim-rout{-webkit-animation-name:layui-m-anim-rout;animation-name:layui-m-anim-rout}.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px}"
  },
  {
    "path": "src/main/webapp/static/layui/css/modules/code.css",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}"
  },
  {
    "path": "src/main/webapp/static/layui/css/modules/laydate/default/laydate.css",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n .laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:laydate-upbit;animation-name:laydate-upbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@-webkit-keyframes laydate-upbit{from{-webkit-transform:translate3d(0,20px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes laydate-upbit{from{transform:translate3d(0,20px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.laydate-set-ym span,.layui-laydate-header i{padding:0 5px;cursor:pointer}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;color:#999;font-size:18px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;height:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px 20px}.layui-laydate-footer span{margin-right:15px;display:inline-block;cursor:pointer;font-size:12px}.layui-laydate-footer span:hover{color:#5FB878}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{height:26px;line-height:26px;margin:0 0 0 -1px;padding:0 10px;border:1px solid #C9C9C9;background-color:#fff;white-space:nowrap;vertical-align:top;border-radius:2px}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-0 .laydate-next-m,.layui-laydate-range .laydate-main-list-0 .laydate-next-y,.layui-laydate-range .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#00F7DE}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eaeaea;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}"
  },
  {
    "path": "src/main/webapp/static/layui/css/modules/layer/default/layer.css",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n .layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+\"px\")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}"
  },
  {
    "path": "src/main/webapp/static/layui/js/firm.js",
    "content": "\n\nlayui.define(['jquery', 'element', 'carousel', 'laypage'], function(exports){\n  var $ = layui.jquery\n  ,element = layui.element\n  ,carousel = layui.carousel\n  ,laypage = layui.laypage;\n\n  //轮播渲染\n  carousel.render({\n    elem: '#banner'\n    ,width: '100%'\n    ,height: '700px'\n    ,arrow: 'always'\n  });\n\n  //滚动监听\n  $(window).scroll(function() {\n    var scr=$(document).scrollTop();\n    scr > 0 ? $(\".nav\").addClass('scroll') : $(\".nav\").removeClass('scroll');\n  });\n\n  //轮播文字\n  $(function(){\n    $('.banner').children('.title').addClass('active');\n  })\n\n  //导航切换\n  var btn = $('.nav').find('.nav-list').children('button')\n  ,spa = btn.children('span')\n  ,ul = $('.nav').find('.nav-list').children('.layui-nav');\n  btn.on('click', function(){\n    if(!$(spa[0]).hasClass('spa1')){\n      spa[0].className = 'spa1';\n      spa[1].style.display = 'none';\n      spa[2].className = 'spa3';\n      $('.nav')[0].style.height = 90 + ul[0].offsetHeight + 'px';\n    }else{\n      spa[0].className = '';\n      spa[1].style.display = 'block';\n      spa[2].className = '';\n      $('.nav')[0].style.height = 80 + 'px';\n    }\n  });\n\n  //关于内容\n  $('.main-about').find('.aboutab').children('li').each(function(index){\n    $(this).on('click', function(){\n      $(this).addClass('layui-this').siblings().removeClass('layui-this');\n      $('.aboutab').siblings().fadeOut(\"fast\");\n      $('.aboutab').siblings().eq(index).fadeIn(\"\");\n    });\n  });\n\n  //动态分页\n  laypage.render({\n    elem: 'newsPage'\n    ,count: 50\n    ,theme: '#2db5a3'\n    ,layout: ['page', 'next']\n  });\n\n  //案例分页\n  laypage.render({\n    elem: 'casePage'\n    ,count: 50\n    ,theme: '#2db5a3' \n    ,layout: ['page', 'next']\n  });\n\n  //新闻字段截取\n  $(function(){\n    $(\".main-news\").find(\".content\").each(function(){\n      var span = $(this).find(\".detail\").children(\"span\")\n      ,spanTxt = span.html();\n      if(document.body.clientWidth > 463){\n        span.html(spanTxt);\n      }else{\n        span.html(span.html().substring(0, 42)+ '...')\n      };\n      $(window).resize(function(){   \n        if(document.body.clientWidth > 463){\n          span.html(spanTxt);\n        }else{\n          span.html(span.html().substring(0, 42)+ '...')\n        };\n      });\n    });\n  });  \n\n  exports('firm', {}); \n});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/carousel.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(e){\"use strict\";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t=\"carousel\",a=\"layui-this\",l=\">*[carousel-item]>*\",o=\"layui-carousel-left\",r=\"layui-carousel-right\",d=\"layui-carousel-prev\",s=\"layui-carousel-next\",u=\"layui-carousel-arrow\",c=\"layui-carousel-ind\",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:\"600px\",height:\"280px\",full:!1,arrow:\"hover\",indicator:\"inside\",autoplay:!0,interval:3e3,anim:\"\",trigger:\"click\",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:\"fixed\",width:\"100%\",height:\"100%\",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr(\"lay-anim\",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['<button class=\"layui-icon '+u+'\" lay-type=\"sub\">'+(\"updown\"===n.anim?\"&#xe619;\":\"&#xe603;\")+\"</button>\",'<button class=\"layui-icon '+u+'\" lay-type=\"add\">'+(\"updown\"===n.anim?\"&#xe61a;\":\"&#xe602;\")+\"</button>\"].join(\"\"));n.elem.attr(\"lay-arrow\",n.arrow),n.elem.find(\".\"+u)[0]&&n.elem.find(\".\"+u).remove(),n.elem.append(t),t.on(\"click\",function(){var n=i(this),t=n.attr(\"lay-type\");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['<div class=\"'+c+'\"><ul>',function(){var i=[];return layui.each(e.elemItem,function(e){i.push(\"<li\"+(n.index===e?' class=\"layui-this\"':\"\")+\"></li>\")}),i.join(\"\")}(),\"</ul></div>\"].join(\"\"));n.elem.attr(\"lay-indicator\",n.indicator),n.elem.find(\".\"+c)[0]&&n.elem.find(\".\"+c).remove(),n.elem.append(t),\"updown\"===n.anim&&t.css(\"margin-top\",-(t.height()/2)),t.find(\"li\").on(\"hover\"===n.trigger?\"mouseover\":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide(\"add\",a-n.index):a<n.index&&e.slide(\"sub\",n.index-a)})},m.prototype.slide=function(e,i){var n=this,l=n.elemItem,u=n.config,c=u.index,m=u.elem.attr(\"lay-filter\");n.haveSlide||(\"sub\"===e?(n.subIndex(i),l.eq(u.index).addClass(d),setTimeout(function(){l.eq(c).addClass(r),l.eq(u.index).addClass(r)},50)):(n.addIndex(i),l.eq(u.index).addClass(s),setTimeout(function(){l.eq(c).addClass(o),l.eq(u.index).addClass(o)},50)),setTimeout(function(){l.removeClass(a+\" \"+d+\" \"+s+\" \"+o+\" \"+r),l.eq(u.index).addClass(a),n.haveSlide=!1},300),n.elemInd.find(\"li\").eq(u.index).addClass(a).siblings().removeClass(a),n.haveSlide=!0,layui.event.call(this,t,\"change(\"+m+\")\",{index:u.index,prevIndex:c,item:l.eq(u.index)}))},m.prototype.events=function(){var e=this,i=e.config;i.elem.data(\"haveEvents\")||(i.elem.on(\"mouseenter\",function(){clearInterval(e.timer)}).on(\"mouseleave\",function(){e.autoplay()}),i.elem.data(\"haveEvents\",!0))},n.render=function(e){var i=new m(e);return i},e(t,n)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/code.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(e){\"use strict\";var a=layui.$,l=\"http://www.layui.com/doc/modules/code.html\";e(\"code\",function(e){var t=[];e=e||{},e.elem=a(e.elem||\".layui-code\"),e.about=!(\"about\"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr(\"lay-encode\")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")),c.html('<ol class=\"layui-code-ol\"><li>'+o.replace(/[\\r\\t\\n]+/g,\"</li><li>\")+\"</li></ol>\"),c.find(\">.layui-code-h3\")[0]||c.prepend('<h3 class=\"layui-code-h3\">'+(c.attr(\"lay-title\")||e.title||\"code\")+(e.about?'<a href=\"'+l+'\" target=\"_blank\">layui.code</a>':\"\")+\"</h3>\");var d=c.find(\">.layui-code-ol\");c.addClass(\"layui-box layui-code-view\"),(c.attr(\"lay-skin\")||e.skin)&&c.addClass(\"layui-code-\"+(c.attr(\"lay-skin\")||e.skin)),(d.find(\"li\").length/100|0)>0&&d.css(\"margin-left\",(d.find(\"li\").length/100|0)+\"px\"),(c.attr(\"lay-height\")||e.height)&&d.css(\"max-height\",c.attr(\"lay-height\")||e.height)})})}).addcss(\"modules/code.css\",\"skincodecss\");"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/colorpicker.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(e){\"use strict\";var i=layui.jquery,o={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var o=this;return o.config=i.extend({},o.config,e),o},on:function(e,i){return layui.onevent.call(this,\"colorpicker\",e,i)}},r=function(){var e=this,i=e.config;return{config:i}},t=\"colorpicker\",n=\"layui-show\",l=\"layui-colorpicker\",c=\".layui-colorpicker-main\",a=\"layui-icon-down\",s=\"layui-icon-close\",f=\"layui-colorpicker-trigger-span\",d=\"layui-colorpicker-trigger-i\",u=\"layui-colorpicker-side\",p=\"layui-colorpicker-side-slider\",g=\"layui-colorpicker-basis\",v=\"layui-colorpicker-alpha-bgcolor\",h=\"layui-colorpicker-alpha-slider\",m=\"layui-colorpicker-basis-cursor\",b=\"layui-colorpicker-main-input\",k=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),t=r-o;return i.b=r,i.s=0!=r?255*t/r:0,0!=i.s?e.r==r?i.h=(e.g-e.b)/t:e.g==r?i.h=2+(e.b-e.r)/t:i.h=4+(e.r-e.g)/t:i.h=-1,r==o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},y=function(e){var e=e.indexOf(\"#\")>-1?e.substring(1):e;if(3==e.length){var i=e.split(\"\");e=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]}e=parseInt(e,16);var o={r:e>>16,g:(65280&e)>>8,b:255&e};return k(o)},x=function(e){var i={},o=e.h,r=255*e.s/100,t=255*e.b/100;if(0==r)i.r=i.g=i.b=t;else{var n=t,l=(255-r)*t/255,c=(n-l)*(o%60)/60;360==o&&(o=0),o<60?(i.r=n,i.b=l,i.g=l+c):o<120?(i.g=n,i.b=l,i.r=n-c):o<180?(i.g=n,i.r=l,i.b=l+c):o<240?(i.b=n,i.r=l,i.g=n-c):o<300?(i.b=n,i.g=l,i.r=l+c):o<360?(i.r=n,i.g=l,i.b=n-c):(i.r=0,i.g=0,i.b=0)}return{r:Math.round(i.r),g:Math.round(i.g),b:Math.round(i.b)}},C=function(e){var o=x(e),r=[o.r.toString(16),o.g.toString(16),o.b.toString(16)];return i.each(r,function(e,i){1==i.length&&(r[e]=\"0\"+i)}),r.join(\"\")},P=function(e){var i=/[0-9]{1,3}/g,o=e.match(i)||[];return{r:o[0],g:o[1],b:o[2]}},B=i(window),w=i(document),D=function(e){var r=this;r.index=++o.index,r.config=i.extend({},r.config,o.config,e),r.render()};D.prototype.config={color:\"\",size:null,alpha:!1,format:\"hex\",predefine:!1,colors:[\"#009688\",\"#5FB878\",\"#1E9FFF\",\"#FF5722\",\"#FFB800\",\"#01AAED\",\"#999\",\"#c00\",\"#ff8c00\",\"#ffd700\",\"#90ee90\",\"#00ced1\",\"#1e90ff\",\"#c71585\",\"rgb(0, 186, 189)\",\"rgb(255, 120, 0)\",\"rgb(250, 212, 0)\",\"#393D49\",\"rgba(0,0,0,.5)\",\"rgba(255, 69, 0, 0.68)\",\"rgba(144, 240, 144, 0.5)\",\"rgba(31, 147, 255, 0.73)\"]},D.prototype.render=function(){var e=this,o=e.config,r=i(['<div class=\"layui-unselect layui-colorpicker\">',\"<span \"+(\"rgb\"==o.format&&o.alpha?'class=\"layui-colorpicker-trigger-bgcolor\"':\"\")+\">\",'<span class=\"layui-colorpicker-trigger-span\" ','lay-type=\"'+(\"rgb\"==o.format?o.alpha?\"rgba\":\"torgb\":\"\")+'\" ','style=\"'+function(){var e=\"\";return o.color?(e=o.color,(o.color.match(/[0-9]{1,3}/g)||[]).length>3&&(o.alpha&&\"rgb\"==o.format||(e=\"#\"+C(k(P(o.color))))),\"background: \"+e):e}()+'\">','<i class=\"layui-icon layui-colorpicker-trigger-i '+(o.color?a:s)+'\"></i>',\"</span>\",\"</span>\",\"</div>\"].join(\"\")),t=i(o.elem);o.size&&r.addClass(\"layui-colorpicker-\"+o.size),t.addClass(\"layui-inline\").html(e.elemColorBox=r),e.color=e.elemColorBox.find(\".\"+f)[0].style.background,e.events()},D.prototype.renderPicker=function(){var e=this,o=e.config,r=e.elemColorBox[0],t=e.elemPicker=i(['<div id=\"layui-colorpicker'+e.index+'\" data-index=\"'+e.index+'\" class=\"layui-anim layui-anim-upbit layui-colorpicker-main\">','<div class=\"layui-colorpicker-main-wrapper\">','<div class=\"layui-colorpicker-basis\">','<div class=\"layui-colorpicker-basis-white\"></div>','<div class=\"layui-colorpicker-basis-black\"></div>','<div class=\"layui-colorpicker-basis-cursor\"></div>',\"</div>\",'<div class=\"layui-colorpicker-side\">','<div class=\"layui-colorpicker-side-slider\"></div>',\"</div>\",\"</div>\",'<div class=\"layui-colorpicker-main-alpha '+(o.alpha?n:\"\")+'\">','<div class=\"layui-colorpicker-alpha-bgcolor\">','<div class=\"layui-colorpicker-alpha-slider\"></div>',\"</div>\",\"</div>\",function(){if(o.predefine){var e=['<div class=\"layui-colorpicker-main-pre\">'];return layui.each(o.colors,function(i,o){e.push(['<div class=\"layui-colorpicker-pre'+((o.match(/[0-9]{1,3}/g)||[]).length>3?\" layui-colorpicker-pre-isalpha\":\"\")+'\">','<div style=\"background:'+o+'\"></div>',\"</div>\"].join(\"\"))}),e.push(\"</div>\"),e.join(\"\")}return\"\"}(),'<div class=\"layui-colorpicker-main-input\">','<div class=\"layui-inline\">','<input type=\"text\" class=\"layui-input\">',\"</div>\",'<div class=\"layui-btn-container\">','<button class=\"layui-btn layui-btn-primary layui-btn-sm\" colorpicker-events=\"clear\">清空</button>','<button class=\"layui-btn layui-btn-sm\" colorpicker-events=\"confirm\">确定</button>',\"</div\",\"</div>\",\"</div>\"].join(\"\"));e.elemColorBox.find(\".\"+f)[0];i(c)[0]&&i(c).data(\"index\")==e.index?e.removePicker(D.thisElemInd):(e.removePicker(D.thisElemInd),i(\"body\").append(t)),D.thisElemInd=e.index,D.thisColor=r.style.background,e.position(),e.pickerEvents()},D.prototype.removePicker=function(e){var o=this;o.config;return i(\"#layui-colorpicker\"+(e||o.index)).remove(),o},D.prototype.position=function(){var e=this,i=e.config,o=e.bindElem||e.elemColorBox[0],r=e.elemPicker[0],t=o.getBoundingClientRect(),n=r.offsetWidth,l=r.offsetHeight,c=function(e){return e=e?\"scrollLeft\":\"scrollTop\",document.body[e]|document.documentElement[e]},a=function(e){return document.documentElement[e?\"clientWidth\":\"clientHeight\"]},s=5,f=t.left,d=t.bottom;f-=(n-o.offsetWidth)/2,d+=s,f+n+s>a(\"width\")?f=a(\"width\")-n-s:f<s&&(f=s),d+l+s>a()&&(d=t.top>l?t.top-l:a()-l,d-=2*s),i.position&&(r.style.position=i.position),r.style.left=f+(\"fixed\"===i.position?0:c(1))+\"px\",r.style.top=d+(\"fixed\"===i.position?0:c())+\"px\"},D.prototype.val=function(){var e=this,i=(e.config,e.elemColorBox.find(\".\"+f)),o=e.elemPicker.find(\".\"+b),r=i[0],t=r.style.backgroundColor;if(t){var n=k(P(t)),l=i.attr(\"lay-type\");if(e.select(n.h,n.s,n.b),\"torgb\"===l&&o.find(\"input\").val(t),\"rgba\"===l){var c=P(t);if(3==(t.match(/[0-9]{1,3}/g)||[]).length)o.find(\"input\").val(\"rgba(\"+c.r+\", \"+c.g+\", \"+c.b+\", 1)\"),e.elemPicker.find(\".\"+h).css(\"left\",280);else{o.find(\"input\").val(t);var a=280*t.slice(t.lastIndexOf(\",\")+1,t.length-1);e.elemPicker.find(\".\"+h).css(\"left\",a)}e.elemPicker.find(\".\"+v)[0].style.background=\"linear-gradient(to right, rgba(\"+c.r+\", \"+c.g+\", \"+c.b+\", 0), rgb(\"+c.r+\", \"+c.g+\", \"+c.b+\"))\"}}else e.select(0,100,100),o.find(\"input\").val(\"\"),e.elemPicker.find(\".\"+v)[0].style.background=\"\",e.elemPicker.find(\".\"+h).css(\"left\",280)},D.prototype.side=function(){var e=this,o=e.config,r=e.elemColorBox.find(\".\"+f),t=r.attr(\"lay-type\"),n=e.elemPicker.find(\".\"+u),l=e.elemPicker.find(\".\"+p),c=e.elemPicker.find(\".\"+g),y=e.elemPicker.find(\".\"+m),C=e.elemPicker.find(\".\"+v),w=e.elemPicker.find(\".\"+h),D=l[0].offsetTop/180*360,E=100-(y[0].offsetTop+3)/180*100,H=(y[0].offsetLeft+3)/260*100,W=Math.round(w[0].offsetLeft/280*100)/100,j=e.elemColorBox.find(\".\"+d),F=e.elemPicker.find(\".layui-colorpicker-pre\").children(\"div\"),L=function(i,n,l,c){e.select(i,n,l);var f=x({h:i,s:n,b:l});if(j.addClass(a).removeClass(s),r[0].style.background=\"rgb(\"+f.r+\", \"+f.g+\", \"+f.b+\")\",\"torgb\"===t&&e.elemPicker.find(\".\"+b).find(\"input\").val(\"rgb(\"+f.r+\", \"+f.g+\", \"+f.b+\")\"),\"rgba\"===t){var d=0;d=280*c,w.css(\"left\",d),e.elemPicker.find(\".\"+b).find(\"input\").val(\"rgba(\"+f.r+\", \"+f.g+\", \"+f.b+\", \"+c+\")\"),r[0].style.background=\"rgba(\"+f.r+\", \"+f.g+\", \"+f.b+\", \"+c+\")\",C[0].style.background=\"linear-gradient(to right, rgba(\"+f.r+\", \"+f.g+\", \"+f.b+\", 0), rgb(\"+f.r+\", \"+f.g+\", \"+f.b+\"))\"}o.change&&o.change(e.elemPicker.find(\".\"+b).find(\"input\").val())},M=i(['<div class=\"layui-auxiliar-moving\" id=\"LAY-colorpicker-moving\"></div'].join(\"\")),Y=function(e){i(\"#LAY-colorpicker-moving\")[0]||i(\"body\").append(M),M.on(\"mousemove\",e),M.on(\"mouseup\",function(){M.remove()}).on(\"mouseleave\",function(){M.remove()})};l.on(\"mousedown\",function(e){var i=this.offsetTop,o=e.clientY,r=function(e){var r=i+(e.clientY-o),t=n[0].offsetHeight;r<0&&(r=0),r>t&&(r=t);var l=r/180*360;D=l,L(l,H,E,W),e.preventDefault()};Y(r),e.preventDefault()}),n.on(\"click\",function(e){var o=e.clientY-i(this).offset().top;o<0&&(o=0),o>this.offsetHeight&&(o=this.offsetHeight);var r=o/180*360;D=r,L(r,H,E,W),e.preventDefault()}),y.on(\"mousedown\",function(e){var i=this.offsetTop,o=this.offsetLeft,r=e.clientY,t=e.clientX,n=function(e){var n=i+(e.clientY-r),l=o+(e.clientX-t),a=c[0].offsetHeight-3,s=c[0].offsetWidth-3;n<-3&&(n=-3),n>a&&(n=a),l<-3&&(l=-3),l>s&&(l=s);var f=(l+3)/260*100,d=100-(n+3)/180*100;E=d,H=f,L(D,f,d,W),e.preventDefault()};layui.stope(e),Y(n),e.preventDefault()}),c.on(\"mousedown\",function(e){var o=e.clientY-i(this).offset().top-3+B.scrollTop(),r=e.clientX-i(this).offset().left-3+B.scrollLeft();o<-3&&(o=-3),o>this.offsetHeight-3&&(o=this.offsetHeight-3),r<-3&&(r=-3),r>this.offsetWidth-3&&(r=this.offsetWidth-3);var t=(r+3)/260*100,n=100-(o+3)/180*100;E=n,H=t,L(D,t,n,W),e.preventDefault(),y.trigger(e,\"mousedown\")}),w.on(\"mousedown\",function(e){var i=this.offsetLeft,o=e.clientX,r=function(e){var r=i+(e.clientX-o),t=C[0].offsetWidth;r<0&&(r=0),r>t&&(r=t);var n=Math.round(r/280*100)/100;W=n,L(D,H,E,n),e.preventDefault()};Y(r),e.preventDefault()}),C.on(\"click\",function(e){var o=e.clientX-i(this).offset().left;o<0&&(o=0),o>this.offsetWidth&&(o=this.offsetWidth);var r=Math.round(o/280*100)/100;W=r,L(D,H,E,r),e.preventDefault()}),F.each(function(){i(this).on(\"click\",function(){i(this).parent(\".layui-colorpicker-pre\").addClass(\"selected\").siblings().removeClass(\"selected\");var e,o=this.style.backgroundColor,r=k(P(o)),t=o.slice(o.lastIndexOf(\",\")+1,o.length-1);D=r.h,H=r.s,E=r.b,3==(o.match(/[0-9]{1,3}/g)||[]).length&&(t=1),W=t,e=280*t,L(r.h,r.s,r.b,t)})})},D.prototype.select=function(e,i,o,r){var t=this,n=(t.config,C({h:e,s:100,b:100})),l=C({h:e,s:i,b:o}),c=e/360*180,a=180-o/100*180-3,s=i/100*260-3;t.elemPicker.find(\".\"+p).css(\"top\",c),t.elemPicker.find(\".\"+g)[0].style.background=\"#\"+n,t.elemPicker.find(\".\"+m).css({top:a,left:s}),\"change\"!==r&&t.elemPicker.find(\".\"+b).find(\"input\").val(\"#\"+l)},D.prototype.pickerEvents=function(){var e=this,o=e.config,r=e.elemColorBox.find(\".\"+f),t=e.elemPicker.find(\".\"+b+\" input\"),n={clear:function(i){r[0].style.background=\"\",e.elemColorBox.find(\".\"+d).removeClass(a).addClass(s),e.color=\"\",o.done&&o.done(\"\"),e.removePicker()},confirm:function(i,n){var l=t.val(),c=l,f={};if(l.indexOf(\",\")>-1){if(f=k(P(l)),e.select(f.h,f.s,f.b),r[0].style.background=c=\"#\"+C(f),(l.match(/[0-9]{1,3}/g)||[]).length>3&&\"rgba\"===r.attr(\"lay-type\")){var u=280*l.slice(l.lastIndexOf(\",\")+1,l.length-1);e.elemPicker.find(\".\"+h).css(\"left\",u),r[0].style.background=l,c=l}}else f=y(l),r[0].style.background=c=\"#\"+C(f),e.elemColorBox.find(\".\"+d).removeClass(s).addClass(a);return\"change\"===n?(e.select(f.h,f.s,f.b,n),void(o.change&&o.change(c))):(e.color=l,o.done&&o.done(l),void e.removePicker())}};e.elemPicker.on(\"click\",\"*[colorpicker-events]\",function(){var e=i(this),o=e.attr(\"colorpicker-events\");n[o]&&n[o].call(this,e)}),t.on(\"keyup\",function(e){var o=i(this);n.confirm.call(this,o,13===e.keyCode?null:\"change\")})},D.prototype.events=function(){var e=this,o=e.config,r=e.elemColorBox.find(\".\"+f);e.elemColorBox.on(\"click\",function(){e.renderPicker(),i(c)[0]&&(e.val(),e.side())}),o.elem[0]&&!e.elemColorBox[0].eventHandler&&(w.on(\"click\",function(o){if(!i(o.target).hasClass(l)&&!i(o.target).parents(\".\"+l)[0]&&!i(o.target).hasClass(c.replace(/\\./g,\"\"))&&!i(o.target).parents(c)[0]&&e.elemPicker){if(e.color){var t=k(P(e.color));e.select(t.h,t.s,t.b)}else e.elemColorBox.find(\".\"+d).removeClass(a).addClass(s);r[0].style.background=e.color||\"\",e.removePicker()}}),B.on(\"resize\",function(){return!(!e.elemPicker||!i(c)[0])&&void e.position()}),e.elemColorBox[0].eventHandler=!0)},o.render=function(e){var i=new D(e);return r.call(i)},e(t,o)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/element.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(t){\"use strict\";var a=layui.$,i=(layui.hint(),layui.device()),e=\"element\",l=\"layui-this\",n=\"layui-show\",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=\".layui-tab-title\",l=a(\".layui-tab[lay-filter=\"+t+\"]\"),n=l.children(e),s=n.children(\".layui-tab-bar\"),o=l.children(\".layui-tab-content\"),r='<li lay-id=\"'+(i.id||\"\")+'\"'+(i.attr?' lay-attr=\"'+i.attr+'\"':\"\")+\">\"+(i.title||\"unnaming\")+\"</li>\";return s[0]?s.before(r):n.append(r),o.append('<div class=\"layui-tab-item\">'+(i.content||\"\")+\"</div>\"),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=\".layui-tab-title\",l=a(\".layui-tab[lay-filter=\"+t+\"]\"),n=l.children(e),s=n.find('>li[lay-id=\"'+i+'\"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=\".layui-tab-title\",l=a(\".layui-tab[lay-filter=\"+t+\"]\"),n=l.children(e),s=n.find('>li[lay-id=\"'+i+'\"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on(\"click\",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e=\"layui-progress\",l=a(\".\"+e+\"[lay-filter=\"+t+\"]\"),n=l.find(\".\"+e+\"-bar\"),s=n.find(\".\"+e+\"-text\");return n.css(\"width\",i),s.text(i),this};var o=\".layui-nav\",r=\"layui-nav-item\",c=\"layui-nav-bar\",u=\"layui-nav-tree\",d=\"layui-nav-child\",y=\"layui-nav-more\",h=\"layui-anim layui-anim-upbit\",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children(\"li\").index(r),c=o.headerElem?r.parent():r.parents(\".layui-tab\").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(\".layui-tab-content\").children(\".layui-tab-item\"),d=r.find(\"a\"),y=c.attr(\"lay-filter\");\"javascript:;\"!==d.attr(\"href\")&&\"_blank\"===d.attr(\"target\")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,\"tab(\"+y+\")\",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(\".layui-tab\").eq(0),r=o.children(\".layui-tab-content\").children(\".layui-tab-item\"),c=o.attr(\"lay-filter\");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,\"tabDelete(\"+c+\")\",{elem:o,index:s})},tabAuto:function(){var t=\"layui-tab-more\",e=\"layui-tab-bar\",l=\"layui-tab-close\",n=this;a(\".layui-tab\").each(function(){var s=a(this),o=s.children(\".layui-tab-title\"),r=(s.children(\".layui-tab-content\").children(\".layui-tab-item\"),'lay-stope=\"tabmore\"'),c=a('<span class=\"layui-unselect layui-tab-bar\" '+r+\"><i \"+r+' class=\"layui-icon\">&#xe61a;</i></span>');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr(\"lay-allowClose\")&&o.find(\"li\").each(function(){var t=a(this);if(!t.find(\".\"+l)[0]){var i=a('<i class=\"layui-icon layui-unselect '+l+'\">&#x1006;</i>');i.on(\"click\",f.tabDelete),t.append(i)}}),\"string\"!=typeof s.attr(\"lay-unauto\"))if(o.prop(\"scrollWidth\")>o.outerWidth()+1){if(o.find(\".\"+e)[0])return;o.append(c),s.attr(\"overflow\",\"\"),c.on(\"click\",function(a){o[this.title?\"removeClass\":\"addClass\"](t),this.title=this.title?\"\":\"收缩\"})}else o.find(\".\"+e).remove(),s.removeAttr(\"overflow\")})},hideTabMore:function(t){var i=a(\".layui-tab-title\");t!==!0&&\"tabmore\"===a(t.target).attr(\"lay-stope\")||(i.removeClass(\"layui-tab-more\"),i.find(\".layui-tab-bar\").attr(\"title\",\"\"))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr(\"lay-filter\"),s=t.parent(),c=t.siblings(\".\"+d),y=\"string\"==typeof s.attr(\"lay-unselect\");\"javascript:;\"!==t.attr(\"href\")&&\"_blank\"===t.attr(\"target\")||y||c[0]||(i.find(\".\"+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s[\"none\"===c.css(\"display\")?\"addClass\":\"removeClass\"](r+\"ed\"),\"all\"===i.attr(\"lay-shrink\")&&s.siblings().removeClass(r+\"ed\"))),layui.event.call(this,e,\"nav(\"+n+\")\",t)},collapse:function(){var t=a(this),i=t.find(\".layui-colla-icon\"),l=t.siblings(\".layui-colla-content\"),s=t.parents(\".layui-collapse\").eq(0),o=s.attr(\"lay-filter\"),r=\"none\"===l.css(\"display\");if(\"string\"==typeof s.attr(\"lay-accordion\")){var c=s.children(\".layui-colla-item\").children(\".\"+n);c.siblings(\".layui-colla-title\").children(\".layui-colla-icon\").html(\"&#xe602;\"),c.removeClass(n)}l[r?\"addClass\":\"removeClass\"](n),i.html(r?\"&#xe61a;\":\"&#xe602;\"),layui.event.call(this,e,\"collapse(\"+o+\")\",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter=\"'+e+'\"]':\"\"}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find(\".\"+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children(\"a\").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css(\"marginLeft\")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),\"block\"===f.css(\"display\")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find(\".\"+y).addClass(y+\"d\")},300))};a(o+l).each(function(i){var l=a(this),o=a('<span class=\"'+c+'\"></span>'),h=l.find(\".\"+r);l.find(\".\"+c)[0]||(l.append(o),h.on(\"mouseenter\",function(){b.call(this,o,l,i)}).on(\"mouseleave\",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find(\".\"+d).removeClass(n),l.find(\".\"+y).removeClass(y+\"d\")},300))}),l.on(\"mouseleave\",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find(\"a\").each(function(){var t=a(this),i=(t.parent(),t.siblings(\".\"+d));i[0]&&!t.children(\".\"+y)[0]&&t.append('<span class=\"'+y+'\"></span>'),t.off(\"click\",f.clickThis).on(\"click\",f.clickThis)})})},breadcrumb:function(){var t=\".layui-breadcrumb\";a(t+l).each(function(){var t=a(this),i=\"lay-separator\",e=t.attr(i)||\"/\",l=t.find(\"a\");l.next(\"span[\"+i+\"]\")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(\"<span \"+i+\">\"+e+\"</span>\")}),t.css(\"visibility\",\"visible\"))})},progress:function(){var t=\"layui-progress\";a(\".\"+t+l).each(function(){var i=a(this),e=i.find(\".layui-progress-bar\"),l=e.attr(\"lay-percent\");e.css(\"width\",function(){return/^.+\\/.+$/.test(l)?100*new Function(\"return \"+l)()+\"%\":l}()),i.attr(\"lay-showPercent\")&&setTimeout(function(){e.html('<span class=\"'+t+'-text\">'+l+\"</span>\")},350)})},collapse:function(){var t=\"layui-collapse\";a(\".\"+t+l).each(function(){var t=a(this).find(\".layui-colla-item\");t.each(function(){var t=a(this),i=t.find(\".layui-colla-title\"),e=t.find(\".layui-colla-content\"),l=\"none\"===e.css(\"display\");i.find(\".layui-colla-icon\").remove(),i.append('<i class=\"layui-icon layui-colla-icon\">'+(l?\"&#xe602;\":\"&#xe61a;\")+\"</i>\"),i.off(\"click\",f.collapse).on(\"click\",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=\".layui-tab-title li\";b.on(\"click\",v,f.tabClick),b.on(\"click\",f.hideTabMore),a(window).on(\"resize\",f.tabAuto),t(e,p)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/flow.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(e){\"use strict\";var l=layui.$,o=function(e){},t='<i class=\"layui-anim layui-anim-rotate layui-anim-loop layui-icon \">&#xe63e;</i>';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!(\"isAuto\"in e)||e.isAuto,v=e.end||\"没有更多了\",y=e.scrollElem&&e.scrollElem!==document,d=\"<cite>加载更多</cite>\",h=l('<div class=\"layui-flow-more\"><a href=\"javascript:;\">'+d+\"</a></div>\");f.find(\".layui-flow-more\")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find(\"a\").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find(\"a\").html(t),\"function\"==typeof e.done&&e.done(++c,p)};if(g(),h.find(\"a\").on(\"click\",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+\" img\",scrollElem:e.scrollElem});return s?(m.on(\"scroll\",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop(\"scrollHeight\"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||\"img\",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr(\"src\")){var m=e.attr(\"lay-src\");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr(\"src\",m).removeAttr(\"lay-src\"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;s<t.lazyimg.elem.length;s++){var v=t.lazyimg.elem.eq(s),y=a?function(){return v.offset().top-n.offset().top+m}():v.offset().top;if(c(v,f),i=s,y>u)break}};if(f(),!o){var m;n.on(\"scroll\",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e(\"flow\",new o)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/form.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"layer\",function(e){\"use strict\";var t=layui.$,i=layui.layer,a=layui.hint(),n=layui.device(),l=\"form\",r=\".layui-form\",s=\"layui-this\",o=\"layui-hide\",c=\"layui-disabled\",u=function(){this.config={verify:{required:[/[\\S]+/,\"必填项不能为空\"],phone:[/^1\\d{10}$/,\"请输入正确的手机号\"],email:[/^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$/,\"邮箱格式不正确\"],url:[/(^#)|(^http(s*):\\/\\/[^\\s]+\\.[^\\s]+)/,\"链接格式不正确\"],number:function(e){if(!e||isNaN(e))return\"只能填写数字\"},date:[/^(\\d{4})[-\\/](\\d{1}|0\\d{1}|1[0-2])([-\\/](\\d{1}|0\\d{1}|[1-2][0-9]|3[0-1]))*$/,\"日期格式不正确\"],identity:[/(^\\d{15}$)|(^\\d{17}(x|X|\\d)$)/,\"请输入正确的身份证号\"]}}};u.prototype.set=function(e){var i=this;return t.extend(!0,i.config,e),i},u.prototype.verify=function(e){var i=this;return t.extend(!0,i.config.verify,e),i},u.prototype.on=function(e,t){return layui.onevent.call(this,l,e,t)},u.prototype.val=function(e,i){var a=t(r+'[lay-filter=\"'+e+'\"]');a.each(function(e,a){var n=t(this);layui.each(i,function(e,t){var i,a=n.find('[name=\"'+e+'\"]');a[0]&&(i=a[0].type,\"checkbox\"===i?a[0].checked=t:\"radio\"===i?a.each(function(){this.value==t&&(this.checked=!0)}):a.val(t))})}),f.render(null,e)},u.prototype.render=function(e,i){var n=this,u=t(r+function(){return i?'[lay-filter=\"'+i+'\"]':\"\"}()),d={select:function(){var e,i=\"请选择\",a=\"layui-form-select\",n=\"layui-select-title\",r=\"layui-select-none\",d=\"\",f=u.find(\"select\"),v=function(i,l){t(i.target).parent().hasClass(n)&&!l||(t(\".\"+a).removeClass(a+\"ed \"+a+\"up\"),e&&d&&e.val(d)),e=null},y=function(i,u,f){var y,p=t(this),m=i.find(\".\"+n),k=m.find(\"input\"),x=i.find(\"dl\"),g=x.children(\"dd\"),b=this.selectedIndex;if(!u){var C=function(){var e=i.offset().top+i.outerHeight()+5-h.scrollTop(),t=x.outerHeight();b=p[0].selectedIndex,i.addClass(a+\"ed\"),g.removeClass(o),y=null,g.eq(b).addClass(s).siblings().removeClass(s),e+t>h.height()&&e>=t&&i.addClass(a+\"up\"),T()},w=function(e){i.removeClass(a+\"ed \"+a+\"up\"),k.blur(),y=null,e||$(k.val(),function(e){var i=p[0].selectedIndex;e&&(d=t(p[0].options[i]).html(),0===i&&d===k.attr(\"placeholder\")&&(d=\"\"),k.val(d||\"\"))})},T=function(){var e=x.children(\"dd.\"+s);if(e[0]){var t=e.position().top,i=x.height(),a=e.height();t>i&&x.scrollTop(t+x.scrollTop()-i+a-5),t<0&&x.scrollTop(t+x.scrollTop()-5)}};m.on(\"click\",function(e){i.hasClass(a+\"ed\")?w():(v(e,!0),C()),x.find(\".\"+r).remove()}),m.find(\".layui-edge\").on(\"click\",function(){k.focus()}),k.on(\"keyup\",function(e){var t=e.keyCode;9===t&&C()}).on(\"keydown\",function(e){var t=e.keyCode;9===t&&w();var i=function(t,a){var n,l;e.preventDefault();var r=function(){var e=x.children(\"dd.\"+s);if(x.children(\"dd.\"+o)[0]&&\"next\"===t){var i=x.children(\"dd:not(.\"+o+\",.\"+c+\")\"),n=i.eq(0).index();if(n>=0&&n<e.index()&&!i.hasClass(s))return i.eq(0).prev()[0]?i.eq(0).prev():x.children(\":last\")}return a&&a[0]?a:y&&y[0]?y:e}();return l=r[t](),n=r[t](\"dd:not(.\"+o+\")\"),l[0]?(y=r[t](),n[0]&&!n.hasClass(c)||!y[0]?(n.addClass(s).siblings().removeClass(s),void T()):i(t,y)):y=null};38===t&&i(\"prev\"),40===t&&i(\"next\"),13===t&&(e.preventDefault(),x.children(\"dd.\"+s).trigger(\"click\"))});var $=function(e,i,a){var n=0;layui.each(g,function(){var i=t(this),l=i.text(),r=l.indexOf(e)===-1;(\"\"===e||\"blur\"===a?e!==l:r)&&n++,\"keyup\"===a&&i[r?\"addClass\":\"removeClass\"](o)});var l=n===g.length;return i(l),l},q=function(e){var t=this.value,i=e.keyCode;return 9!==i&&13!==i&&37!==i&&38!==i&&39!==i&&40!==i&&($(t,function(e){e?x.find(\".\"+r)[0]||x.append('<p class=\"'+r+'\">无匹配项</p>'):x.find(\".\"+r).remove()},\"keyup\"),\"\"===t&&x.find(\".\"+r).remove(),void T())};f&&k.on(\"keyup\",q).on(\"blur\",function(i){var a=p[0].selectedIndex;e=k,d=t(p[0].options[a]).html(),0===a&&d===k.attr(\"placeholder\")&&(d=\"\"),setTimeout(function(){$(k.val(),function(e){d||k.val(\"\")},\"blur\")},200)}),g.on(\"click\",function(){var e=t(this),a=e.attr(\"lay-value\"),n=p.attr(\"lay-filter\");return!e.hasClass(c)&&(e.hasClass(\"layui-select-tips\")?k.val(\"\"):(k.val(e.text()),e.addClass(s)),e.siblings().removeClass(s),p.val(a).removeClass(\"layui-form-danger\"),layui.event.call(this,l,\"select(\"+n+\")\",{elem:p[0],value:a,othis:i}),w(!0),!1)}),i.find(\"dl>dt\").on(\"click\",function(e){return!1}),t(document).off(\"click\",v).on(\"click\",v)}};f.each(function(e,l){var r=t(this),o=r.next(\".\"+a),u=this.disabled,d=l.value,f=t(l.options[l.selectedIndex]),v=l.options[0];if(\"string\"==typeof r.attr(\"lay-ignore\"))return r.show();var h=\"string\"==typeof r.attr(\"lay-search\"),p=v?v.value?i:v.innerHTML||i:i,m=t(['<div class=\"'+(h?\"\":\"layui-unselect \")+a,(u?\" layui-select-disabled\":\"\")+'\">','<div class=\"'+n+'\">','<input type=\"text\" placeholder=\"'+p+'\" '+('value=\"'+(d?f.html():\"\")+'\"')+(h?\"\":\" readonly\")+' class=\"layui-input'+(h?\"\":\" layui-unselect\")+(u?\" \"+c:\"\")+'\">','<i class=\"layui-edge\"></i></div>','<dl class=\"layui-anim layui-anim-upbit'+(r.find(\"optgroup\")[0]?\" layui-select-group\":\"\")+'\">',function(e){var t=[];return layui.each(e,function(e,a){0!==e||a.value?\"optgroup\"===a.tagName.toLowerCase()?t.push(\"<dt>\"+a.label+\"</dt>\"):t.push('<dd lay-value=\"'+a.value+'\" class=\"'+(d===a.value?s:\"\")+(a.disabled?\" \"+c:\"\")+'\">'+a.innerHTML+\"</dd>\"):t.push('<dd lay-value=\"\" class=\"layui-select-tips\">'+(a.innerHTML||i)+\"</dd>\")}),0===t.length&&t.push('<dd lay-value=\"\" class=\"'+c+'\">没有选项</dd>'),t.join(\"\")}(r.find(\"*\"))+\"</dl>\",\"</div>\"].join(\"\"));o[0]&&o.remove(),r.after(m),y.call(this,m,u,h)})},checkbox:function(){var e={checkbox:[\"layui-form-checkbox\",\"layui-form-checked\",\"checkbox\"],_switch:[\"layui-form-switch\",\"layui-form-onswitch\",\"switch\"]},i=u.find(\"input[type=checkbox]\"),a=function(e,i){var a=t(this);e.on(\"click\",function(){var t=a.attr(\"lay-filter\"),n=(a.attr(\"lay-text\")||\"\").split(\"|\");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(i[1]).find(\"em\").text(n[1])):(a[0].checked=!0,e.addClass(i[1]).find(\"em\").text(n[0])),layui.event.call(a[0],l,i[2]+\"(\"+t+\")\",{elem:a[0],value:a[0].value,othis:e}))})};i.each(function(i,n){var l=t(this),r=l.attr(\"lay-skin\"),s=(l.attr(\"lay-text\")||\"\").split(\"|\"),o=this.disabled;\"switch\"===r&&(r=\"_\"+r);var u=e[r]||e.checkbox;if(\"string\"==typeof l.attr(\"lay-ignore\"))return l.show();var d=l.next(\".\"+u[0]),f=t(['<div class=\"layui-unselect '+u[0],n.checked?\" \"+u[1]:\"\",o?\" layui-checkbox-disbaled \"+c:\"\",'\"',r?' lay-skin=\"'+r+'\"':\"\",\">\",function(){var e=n.title.replace(/\\s/g,\"\"),t={checkbox:[e?\"<span>\"+n.title+\"</span>\":\"\",'<i class=\"layui-icon layui-icon-ok\"></i>'].join(\"\"),_switch:\"<em>\"+((n.checked?s[0]:s[1])||\"\")+\"</em><i></i>\"};return t[r]||t.checkbox}(),\"</div>\"].join(\"\"));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e=\"layui-form-radio\",i=[\"&#xe643;\",\"&#xe63f;\"],a=u.find(\"input[type=radio]\"),n=function(a){var n=t(this),s=\"layui-anim-scaleSpring\";a.on(\"click\",function(){var o=n[0].name,c=n.parents(r),u=n.attr(\"lay-filter\"),d=c.find(\"input[name=\"+o.replace(/(\\.|#|\\[|\\])/g,\"\\\\$1\")+\"]\");n[0].disabled||(layui.each(d,function(){var a=t(this).next(\".\"+e);this.checked=!1,a.removeClass(e+\"ed\"),a.find(\".layui-icon\").removeClass(s).html(i[1])}),n[0].checked=!0,a.addClass(e+\"ed\"),a.find(\".layui-icon\").addClass(s).html(i[0]),layui.event.call(n[0],l,\"radio(\"+u+\")\",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=t(this),s=r.next(\".\"+e),o=this.disabled;if(\"string\"==typeof r.attr(\"lay-ignore\"))return r.show();s[0]&&s.remove();var u=t(['<div class=\"layui-unselect '+e,l.checked?\" \"+e+\"ed\":\"\",(o?\" layui-radio-disbaled \"+c:\"\")+'\">','<i class=\"layui-anim layui-icon\">'+i[l.checked?0:1]+\"</i>\",\"<div>\"+function(){var e=l.title||\"\";return\"string\"==typeof r.next().attr(\"lay-radio\")&&(e=r.next().html(),r.next().remove()),e}()+\"</div>\",\"</div>\"].join(\"\"));r.after(u),n.call(this,u)})}};return e?d[e]?d[e]():a.error(\"不支持的\"+e+\"表单渲染\"):layui.each(d,function(e,t){t()}),n};var d=function(){var e=t(this),a=f.config.verify,s=null,o=\"layui-form-danger\",c={},u=e.parents(r),d=u.find(\"*[lay-verify]\"),v=e.parents(\"form\")[0],h=u.find(\"input,select,textarea\"),y=e.attr(\"lay-filter\");if(layui.each(d,function(e,l){var r=t(this),c=r.attr(\"lay-verify\").split(\"|\"),u=r.attr(\"lay-verType\"),d=r.val();if(r.removeClass(o),layui.each(c,function(e,t){var c,f=\"\",v=\"function\"==typeof a[t];if(a[t]){var c=v?f=a[t](d,l):!a[t][0].test(d);if(f=f||a[t][1],\"required\"===t&&(f=r.attr(\"lay-reqText\")||f),c)return\"tips\"===u?i.tips(f,function(){return\"string\"==typeof r.attr(\"lay-ignore\")||\"select\"!==l.tagName.toLowerCase()&&!/^checkbox|radio$/.test(l.type)?r:r.next()}(),{tips:1}):\"alert\"===u?i.alert(f,{title:\"提示\",shadeClose:!0}):i.msg(f,{icon:5,shift:6}),n.android||n.ios||setTimeout(function(){l.focus()},7),r.addClass(o),s=!0}}),s)return s}),s)return!1;var p={};return layui.each(h,function(e,t){if(t.name=(t.name||\"\").replace(/^\\s*|\\s*&/,\"\"),t.name){if(/^.*\\[\\]$/.test(t.name)){var i=t.name.match(/^(.*)\\[\\]$/g)[0];p[i]=0|p[i],t.name=t.name.replace(/^(.*)\\[\\]$/,\"$1[\"+p[i]++ +\"]\")}/^checkbox|radio$/.test(t.type)&&!t.checked||(c[t.name]=t.value)}}),layui.event.call(this,l,\"submit(\"+y+\")\",{elem:this,form:v,field:c})},f=new u,v=t(document),h=t(window);f.render(),v.on(\"reset\",r,function(){var e=t(this).attr(\"lay-filter\");setTimeout(function(){f.render(null,e)},50)}),v.on(\"submit\",r,d).on(\"click\",\"*[lay-submit]\",d),e(l,f)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/jquery.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;!function(e,t){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(e,t){function n(e){var t=!!e&&\"length\"in e&&e.length,n=pe.type(e);return\"function\"!==n&&!pe.isWindow(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&t>0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if(\"string\"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener(\"DOMContentLoaded\",s),e.removeEventListener(\"load\",s)):(re.detachEvent(\"onreadystatechange\",s),e.detachEvent(\"onload\",s))}function s(){(re.addEventListener||\"load\"===e.event.type||\"complete\"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r=\"data-\"+t.replace(_e,\"-$1\").toLowerCase();if(n=e.getAttribute(r),\"string\"==typeof n){try{n=\"true\"===n||\"false\"!==n&&(\"null\"===n?null:+n+\"\"===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if((\"data\"!==t||!pe.isEmptyObject(e[t]))&&\"toJSON\"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||\"string\"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),\"object\"!=typeof t&&\"function\"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),\"string\"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(\" \")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,\"\")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?\"\":\"px\"),c=(pe.cssNumber[t]||\"px\"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||\".5\",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}function p(e){var t=ze.split(\"|\"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,\"globalEval\",!t||pe._data(t[r],\"globalEval\"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x<d;x++)if(a=e[x],a||0===a)if(\"object\"===pe.type(a))pe.merge(v,a.nodeType?[a]:a);else if(Ue.test(a)){for(u=u||y.appendChild(t.createElement(\"div\")),l=(We.exec(a)||[\"\",\"\"])[1].toLowerCase(),f=Xe[l]||Xe._default,u.innerHTML=f[1]+pe.htmlPrefilter(a)+f[2],o=f[0];o--;)u=u.lastChild;if(!fe.leadingWhitespace&&$e.test(a)&&v.push(t.createTextNode($e.exec(a)[0])),!fe.tbody)for(a=\"table\"!==l||Ve.test(a)?\"<table>\"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],\"tbody\")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent=\"\";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,\"input\"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),\"script\"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||\"\")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){\"string\"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,\"table\")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,\"tr\")?e.getElementsByTagName(\"tbody\")[0]||e.appendChild(e.ownerDocument.createElement(\"tbody\")):e}function C(e){return e.type=(null!==pe.find.attr(e,\"type\"))+\"/\"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute(\"type\"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r<i;r++)pe.event.add(t,n,s[n][r])}a.data&&(a.data=pe.extend({},a.data))}}function k(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!fe.noCloneEvent&&t[pe.expando]){i=pe._data(t);for(r in i.events)pe.removeEvent(t,r,i.handle);t.removeAttribute(pe.expando)}\"script\"===n&&t.text!==e.text?(C(t).text=e.text,E(t)):\"object\"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),fe.html5Clone&&e.innerHTML&&!pe.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):\"input\"===n&&Be.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):\"option\"===n?t.defaultSelected=t.selected=e.defaultSelected:\"input\"!==n&&\"textarea\"!==n||(t.defaultValue=e.defaultValue)}}function S(e,t,n,r){t=oe.apply([],t);var i,o,a,s,u,l,c=0,f=e.length,d=f-1,p=t[0],g=pe.isFunction(p);if(g||f>1&&\"string\"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,\"script\"),C),a=s.length;c<f;c++)o=l,c!==d&&(o=pe.clone(o,!0,!0),a&&pe.merge(s,h(o,\"script\"))),n.call(e[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,pe.map(s,E),c=0;c<a;c++)o=s[c],Ie.test(o.type||\"\")&&!pe._data(o,\"globalEval\")&&pe.contains(u,o)&&(o.src?pe._evalUrl&&pe._evalUrl(o.src):pe.globalEval((o.text||o.textContent||o.innerHTML||\"\").replace(ot,\"\")));l=i=null}return e}function A(e,t,n){for(var r,i=t?pe.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||pe.cleanData(h(r)),r.parentNode&&(n&&pe.contains(r.ownerDocument,r)&&g(h(r,\"script\")),r.parentNode.removeChild(r));return e}function D(e,t){var n=pe(t.createElement(e)).appendTo(t.body),r=pe.css(n[0],\"display\");return n.detach(),r}function j(e){var t=re,n=lt[e];return n||(n=D(e,t),\"none\"!==n&&n||(ut=(ut||pe(\"<iframe frameborder='0' width='0' height='0'/>\")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a<s;a++)r=e[a],r.style&&(o[a]=pe._data(r,\"olddisplay\"),n=r.style.display,t?(o[a]||\"none\"!==n||(r.style.display=\"\"),\"\"===r.style.display&&Re(r)&&(o[a]=pe._data(r,\"olddisplay\",j(r.nodeName)))):(i=Re(r),(n&&\"none\"!==n||!i)&&pe._data(r,\"olddisplay\",i?n:pe.css(r,\"display\"))));for(a=0;a<s;a++)r=e[a],r.style&&(t&&\"none\"!==r.style.display&&\"\"!==r.style.display||(r.style.display=t?o[a]||\"\":\"none\"));return e}function _(e,t,n){var r=bt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||\"px\"):t}function F(e,t,n,r,i){for(var o=n===(r?\"border\":\"content\")?4:\"width\"===t?1:0,a=0;o<4;o+=2)\"margin\"===n&&(a+=pe.css(e,n+Oe[o],!0,i)),r?(\"content\"===n&&(a-=pe.css(e,\"padding\"+Oe[o],!0,i)),\"margin\"!==n&&(a-=pe.css(e,\"border\"+Oe[o]+\"Width\",!0,i))):(a+=pe.css(e,\"padding\"+Oe[o],!0,i),\"padding\"!==n&&(a+=pe.css(e,\"border\"+Oe[o]+\"Width\",!0,i)));return a}function M(t,n,r){var i=!0,o=\"width\"===n?t.offsetWidth:t.offsetHeight,a=ht(t),s=fe.boxSizing&&\"border-box\"===pe.css(t,\"boxSizing\",!1,a);if(re.msFullscreenElement&&e.top!==e&&t.getClientRects().length&&(o=Math.round(100*t.getBoundingClientRect()[n])),o<=0||null==o){if(o=gt(t,n,a),(o<0||null==o)&&(o=t.style[n]),ft.test(o))return o;i=s&&(fe.boxSizingReliable()||o===t.style[n]),o=parseFloat(o)||0}return o+F(t,n,r||(s?\"border\":\"content\"),i,a)+\"px\"}function O(e,t,n,r,i){return new O.prototype.init(e,t,n,r,i)}function R(){return e.setTimeout(function(){Nt=void 0}),Nt=pe.now()}function P(e,t){var n,r={height:e},i=0;for(t=t?1:0;i<4;i+=2-t)n=Oe[i],r[\"margin\"+n]=r[\"padding\"+n]=e;return t&&(r.opacity=r.width=e),r}function B(e,t,n){for(var r,i=($.tweeners[t]||[]).concat($.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function W(e,t,n){var r,i,o,a,s,u,l,c,f=this,d={},p=e.style,h=e.nodeType&&Re(e),g=pe._data(e,\"fxshow\");n.queue||(s=pe._queueHooks(e,\"fx\"),null==s.unqueued&&(s.unqueued=0,u=s.empty.fire,s.empty.fire=function(){s.unqueued||u()}),s.unqueued++,f.always(function(){f.always(function(){s.unqueued--,pe.queue(e,\"fx\").length||s.empty.fire()})})),1===e.nodeType&&(\"height\"in t||\"width\"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],l=pe.css(e,\"display\"),c=\"none\"===l?pe._data(e,\"olddisplay\")||j(e.nodeName):l,\"inline\"===c&&\"none\"===pe.css(e,\"float\")&&(fe.inlineBlockNeedsLayout&&\"inline\"!==j(e.nodeName)?p.zoom=1:p.display=\"inline-block\")),n.overflow&&(p.overflow=\"hidden\",fe.shrinkWrapBlocks()||f.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],St.exec(i)){if(delete t[r],o=o||\"toggle\"===i,i===(h?\"hide\":\"show\")){if(\"show\"!==i||!g||void 0===g[r])continue;h=!0}d[r]=g&&g[r]||pe.style(e,r)}else l=void 0;if(pe.isEmptyObject(d))\"inline\"===(\"none\"===l?j(e.nodeName):l)&&(p.display=l);else{g?\"hidden\"in g&&(h=g.hidden):g=pe._data(e,\"fxshow\",{}),o&&(g.hidden=!h),h?pe(e).show():f.done(function(){pe(e).hide()}),f.done(function(){var t;pe._removeData(e,\"fxshow\");for(t in d)pe.style(e,t,d[t])});for(r in d)a=B(h?g[r]:0,r,f),r in g||(g[r]=a.start,h&&(a.end=a.start,a.start=\"width\"===r||\"height\"===r?1:0))}}function I(e,t){var n,r,i,o,a;for(n in e)if(r=pe.camelCase(n),i=t[r],o=e[n],pe.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=pe.cssHooks[r],a&&\"expand\"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function $(e,t,n){var r,i,o=0,a=$.prefilters.length,s=pe.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=Nt||R(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;a<u;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),o<1&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:pe.extend({},t),opts:pe.extend(!0,{specialEasing:{},easing:pe.easing._default},n),originalProperties:t,originalOptions:n,startTime:Nt||R(),duration:n.duration,tweens:[],createTween:function(t,n){var r=pe.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?(s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l,t])):s.rejectWith(e,[l,t]),this}}),c=l.props;for(I(c,l.opts.specialEasing);o<a;o++)if(r=$.prefilters[o].call(l,e,c,l.opts))return pe.isFunction(r.stop)&&(pe._queueHooks(l.elem,l.opts.queue).stop=pe.proxy(r.stop,r)),r;return pe.map(c,B,l),pe.isFunction(l.opts.start)&&l.opts.start.call(e,l),pe.fx.timer(pe.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function z(e){return pe.attr(e,\"class\")||\"\"}function X(e){return function(t,n){\"string\"!=typeof t&&(n=t,t=\"*\");var r,i=0,o=t.toLowerCase().match(De)||[];if(pe.isFunction(n))for(;r=o[i++];)\"+\"===r.charAt(0)?(r=r.slice(1)||\"*\",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function U(e,t,n,r){function i(s){var u;return o[s]=!0,pe.each(e[s]||[],function(e,s){var l=s(t,n,r);return\"string\"!=typeof l||a||o[l]?a?!(u=l):void 0:(t.dataTypes.unshift(l),i(l),!1)}),u}var o={},a=e===Qt;return i(t.dataTypes[0])||!o[\"*\"]&&i(\"*\")}function V(e,t){var n,r,i=pe.ajaxSettings.flatOptions||{};for(r in t)void 0!==t[r]&&((i[r]?e:n||(n={}))[r]=t[r]);return n&&pe.extend(!0,e,n),e}function Y(e,t,n){for(var r,i,o,a,s=e.contents,u=e.dataTypes;\"*\"===u[0];)u.shift(),void 0===i&&(i=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(i)for(a in s)if(s[a]&&s[a].test(i)){u.unshift(a);break}if(u[0]in n)o=u[0];else{for(a in n){if(!u[0]||e.converters[a+\" \"+u[0]]){o=a;break}r||(r=a)}o=o||r}if(o)return o!==u[0]&&u.unshift(o),n[o]}function J(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(a=l[u+\" \"+o]||l[\"* \"+o],!a)for(i in l)if(s=i.split(\" \"),s[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){a===!0?a=l[i]:l[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(f){return{state:\"parsererror\",error:a?f:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}function G(e){return e.style&&e.style.display||pe.css(e,\"display\")}function K(e){for(;e&&1===e.nodeType;){if(\"none\"===G(e)||\"hidden\"===e.type)return!0;e=e.parentNode}return!1}function Q(e,t,n,r){var i;if(pe.isArray(t))pe.each(t,function(t,i){n||rn.test(e)?r(e,i):Q(e+\"[\"+(\"object\"==typeof i&&null!=i?t:\"\")+\"]\",i,n,r)});else if(n||\"object\"!==pe.type(t))r(e,t);else for(i in t)Q(e+\"[\"+i+\"]\",t[i],n,r)}function Z(){try{return new e.XMLHttpRequest}catch(t){}}function ee(){try{return new e.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(t){}}function te(e){return pe.isWindow(e)?e:9===e.nodeType&&(e.defaultView||e.parentWindow)}var ne=[],re=e.document,ie=ne.slice,oe=ne.concat,ae=ne.push,se=ne.indexOf,ue={},le=ue.toString,ce=ue.hasOwnProperty,fe={},de=\"1.12.3\",pe=function(e,t){return new pe.fn.init(e,t)},he=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,ge=/^-ms-/,me=/-([\\da-z])/gi,ye=function(e,t){return t.toUpperCase()};pe.fn=pe.prototype={jquery:de,constructor:pe,selector:\"\",length:0,toArray:function(){return ie.call(this)},get:function(e){return null!=e?e<0?this[e+this.length]:this[e]:ie.call(this)},pushStack:function(e){var t=pe.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e){return pe.each(this,e)},map:function(e){return this.pushStack(pe.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(ie.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:ae,sort:ne.sort,splice:ne.splice},pe.extend=pe.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||pe.isFunction(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(i=arguments[s]))for(r in i)e=a[r],n=i[r],a!==n&&(l&&n&&(pe.isPlainObject(n)||(t=pe.isArray(n)))?(t?(t=!1,o=e&&pe.isArray(e)?e:[]):o=e&&pe.isPlainObject(e)?e:{},a[r]=pe.extend(l,o,n)):void 0!==n&&(a[r]=n));return a},pe.extend({expando:\"jQuery\"+(de+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isFunction:function(e){return\"function\"===pe.type(e)},isArray:Array.isArray||function(e){return\"array\"===pe.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){var t=e&&e.toString();return!pe.isArray(e)&&t-parseFloat(t)+1>=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||\"object\"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,\"constructor\")&&!ce.call(e.constructor.prototype,\"isPrototypeOf\"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?ue[le.call(e)]||\"object\":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,\"ms-\").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;i<r&&t.call(e[i],i,e[i])!==!1;i++);else for(i in e)if(t.call(e[i],i,e[i])===!1)break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(he,\"\")},makeArray:function(e,t){var r=t||[];return null!=e&&(n(Object(e))?pe.merge(r,\"string\"==typeof e?[e]:e):ae.call(r,e)),r},inArray:function(e,t,n){var r;if(t){if(se)return se.call(t,e,n);for(r=t.length,n=n?n<0?Math.max(0,r+n):n:0;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;)e[i++]=t[r++];if(n!==n)for(;void 0!==t[r];)e[i++]=t[r++];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)r=!t(e[o],o),r!==s&&i.push(e[o]);return i},map:function(e,t,r){var i,o,a=0,s=[];if(n(e))for(i=e.length;a<i;a++)o=t(e[a],a,r),null!=o&&s.push(o);else for(a in e)o=t(e[a],a,r),null!=o&&s.push(o);return oe.apply([],s)},guid:1,proxy:function(e,t){var n,r,i;if(\"string\"==typeof t&&(i=e[t],t=e,e=i),pe.isFunction(e))return n=ie.call(arguments,2),r=function(){return e.apply(t||this,n.concat(ie.call(arguments)))},r.guid=e.guid=e.guid||pe.guid++,r},now:function(){return+new Date},support:fe}),\"function\"==typeof Symbol&&(pe.fn[Symbol.iterator]=ne[Symbol.iterator]),pe.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){ue[\"[object \"+t+\"]\"]=t.toLowerCase()});var ve=function(e){function t(e,t,n,r){var i,o,a,s,u,l,f,p,h=t&&t.ownerDocument,g=t?t.nodeType:9;if(n=n||[],\"string\"!=typeof e||!e||1!==g&&9!==g&&11!==g)return n;if(!r&&((t?t.ownerDocument||t:B)!==H&&L(t),t=t||H,_)){if(11!==g&&(l=ye.exec(e)))if(i=l[1]){if(9===g){if(!(a=t.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(h&&(a=h.getElementById(i))&&R(t,a)&&a.id===i)return n.push(a),n}else{if(l[2])return Q.apply(n,t.getElementsByTagName(e)),n;if((i=l[3])&&w.getElementsByClassName&&t.getElementsByClassName)return Q.apply(n,t.getElementsByClassName(i)),n}if(w.qsa&&!X[e+\" \"]&&(!F||!F.test(e))){if(1!==g)h=t,p=e;else if(\"object\"!==t.nodeName.toLowerCase()){for((s=t.getAttribute(\"id\"))?s=s.replace(xe,\"\\\\$&\"):t.setAttribute(\"id\",s=P),f=N(e),o=f.length,u=de.test(s)?\"#\"+s:\"[id='\"+s+\"']\";o--;)f[o]=u+\" \"+d(f[o]);p=f.join(\",\"),h=ve.test(e)&&c(t.parentNode)||t}if(p)try{return Q.apply(n,h.querySelectorAll(p)),n}catch(m){}finally{s===P&&t.removeAttribute(\"id\")}}}return S(e.replace(se,\"$1\"),t,n,r)}function n(){function e(n,r){return t.push(n+\" \")>T.cacheLength&&delete e[t.shift()],e[n+\" \"]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement(\"div\");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split(\"|\"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return\"input\"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return(\"input\"===n||\"button\"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function p(e,t,n){var r=t.dir,i=n&&\"parentNode\"===r,o=I++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,u,l,c=[W,o];if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i){if(l=t[P]||(t[P]={}),u=l[t.uniqueID]||(l[t.uniqueID]={}),(s=u[r])&&s[0]===W&&s[1]===o)return c[2]=s[2];if(u[r]=c,c[2]=e(t,n,a))return!0}}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i<o;i++)t(e,n[i],r);return r}function m(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function y(e,t,n,i,o,a){return i&&!i[P]&&(i=y(i)),o&&!o[P]&&(o=y(o,a)),r(function(r,a,s,u){var l,c,f,d=[],p=[],h=a.length,y=r||g(t||\"*\",s.nodeType?[s]:s,[]),v=!e||!r&&t?y:m(y,d,e,s,u),x=n?o||(r?e:h||i)?[]:a:v;if(n&&n(v,x,s,u),i)for(l=m(x,p),i(l,[],s,u),c=l.length;c--;)(f=l[c])&&(x[p[c]]=!(v[p[c]]=f));if(r){if(o||e){if(o){for(l=[],c=x.length;c--;)(f=x[c])&&l.push(v[c]=f);o(null,x=[],l,u)}for(c=x.length;c--;)(f=x[c])&&(l=o?ee(r,f):d[c])>-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[\" \"],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s<i;s++)if(n=T.relative[e[s].type])c=[p(h(c),n)];else{if(n=T.filter[e[s].type].apply(null,e[s].matches),n[P]){for(r=++s;r<i&&!T.relative[e[r].type];r++);return y(s>1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(se,\"$1\"),n,s<r&&v(e.slice(s,r)),r<i&&v(e=e.slice(r)),r<i&&d(e))}c.push(n)}return h(c)}function x(e,n){var i=n.length>0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h=\"0\",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG(\"*\",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P=\"sizzle\"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},te=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",ne=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",re=\"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",ie=\"\\\\[\"+ne+\"*(\"+re+\")(?:\"+ne+\"*([*^$|!~]?=)\"+ne+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+re+\"))|)\"+ne+\"*\\\\]\",oe=\":(\"+re+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+ie+\")*)|.*)\\\\)|)\",ae=new RegExp(ne+\"+\",\"g\"),se=new RegExp(\"^\"+ne+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+ne+\"+$\",\"g\"),ue=new RegExp(\"^\"+ne+\"*,\"+ne+\"*\"),le=new RegExp(\"^\"+ne+\"*([>+~]|\"+ne+\")\"+ne+\"*\"),ce=new RegExp(\"=\"+ne+\"*([^\\\\]'\\\"]*?)\"+ne+\"*\\\\]\",\"g\"),fe=new RegExp(oe),de=new RegExp(\"^\"+re+\"$\"),pe={ID:new RegExp(\"^#(\"+re+\")\"),CLASS:new RegExp(\"^\\\\.(\"+re+\")\"),TAG:new RegExp(\"^(\"+re+\"|[*])\"),ATTR:new RegExp(\"^\"+ie),PSEUDO:new RegExp(\"^\"+oe),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+ne+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+ne+\"*(?:([+-]|)\"+ne+\"*(\\\\d+)|))\"+ne+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+te+\")$\",\"i\"),needsContext:new RegExp(\"^\"+ne+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+ne+\"*((?:-\\\\d)?\\\\d*)\"+ne+\"*\\\\)|)(?=[^-]|$)\",\"i\")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\\d$/i,me=/^[^{]+\\{\\s*\\[native \\w/,ye=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ve=/[+~]/,xe=/'|\\\\/g,be=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+ne+\"?|(\"+ne+\")|.)\",\"ig\"),we=function(e,t,n){var r=\"0x\"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&\"HTML\"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",Te,!1):n.attachEvent&&n.attachEvent(\"onunload\",Te)),w.attributes=i(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute(\"id\")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML=\"<a id='\"+P+\"'></a><select id='\"+P+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&F.push(\"[*^$]=\"+ne+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||F.push(\"\\\\[\"+ne+\"*(?:value|\"+te+\")\"),e.querySelectorAll(\"[id~=\"+P+\"-]\").length||F.push(\"~=\"),e.querySelectorAll(\":checked\").length||F.push(\":checked\"),e.querySelectorAll(\"a#\"+P+\"+*\").length||F.push(\".#.+[+~]\")}),i(function(e){var t=H.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&F.push(\"name\"+ne+\"*[*^$|!~]?=\"),e.querySelectorAll(\":enabled\").length||F.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),F.push(\",.*:\")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,\"div\"),O.call(e,\"[s!='']:x\"),M.push(\"!=\",oe)}),F=F.length&&new RegExp(F.join(\"|\")),M=M.length&&new RegExp(M.join(\"|\")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,\"='$1']\"),w.matchesSelector&&_&&!X[n+\" \"]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,we),e[3]=(e[3]||e[4]||e[5]||\"\").replace(be,we),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&fe.test(n)&&(t=N(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(be,we).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+\" \"];return t||(t=new RegExp(\"(^|\"+ne+\")\"+e+\"(\"+ne+\"|$)\"))&&$(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?\"!=\"===n:!n||(o+=\"\",\"=\"===n?o===r:\"!=\"===n?o!==r:\"^=\"===n?r&&0===o.indexOf(r):\"*=\"===n?r&&o.indexOf(r)>-1:\"$=\"===n?r&&o.slice(-r.length)===r:\"~=\"===n?(\" \"+o.replace(ae,\" \")+\" \").indexOf(r)>-1:\"|=\"===n&&(o===r||o.slice(0,r.length+1)===r+\"-\"))}},CHILD:function(e,t,n,r,i){var o=\"nth\"!==e.slice(0,3),a=\"last\"!==e.slice(-4),s=\"of-type\"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?\"nextSibling\":\"previousSibling\",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g=\"only\"===e&&!h&&\"nextSibling\"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),\nl=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error(\"unsupported pseudo: \"+e);return o[P]?o(n):o.length>1?(i=[e,e,\"\",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,\"$1\"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||\"\")||t.error(\"unsupported lang: \"+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute(\"xml:lang\")||t.getAttribute(\"lang\"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+\"-\");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:l(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:l(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},T.pseudos.nth=T.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})T.pseudos[b]=s(b);for(b in{submit:!0,reset:!0})T.pseudos[b]=u(b);return f.prototype=T.filters=T.pseudos,T.setFilters=new f,N=t.tokenize=function(e,n){var r,i,o,a,s,u,l,c=z[e+\" \"];if(c)return n?0:c.slice(0);for(s=e,u=[],l=T.preFilter;s;){r&&!(i=ue.exec(s))||(i&&(s=s.slice(i[0].length)||s),u.push(o=[])),r=!1,(i=le.exec(s))&&(r=i.shift(),o.push({value:r,type:i[0].replace(se,\" \")}),s=s.slice(r.length));for(a in T.filter)!(i=pe[a].exec(s))||l[a]&&!(i=l[a](i))||(r=i.shift(),o.push({value:r,type:a,matches:i}),s=s.slice(r.length));if(!r)break}return n?s.length:s?t.error(e):z(e,u).slice(0)},k=t.compile=function(e,t){var n,r=[],i=[],o=X[e+\" \"];if(!o){for(t||(t=N(e)),n=t.length;n--;)o=v(t[n]),o[P]?r.push(o):i.push(o);o=X(e,x(i,r)),o.selector=e}return o},S=t.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,f=!r&&N(e=l.selector||e);if(n=n||[],1===f.length){if(o=f[0]=f[0].slice(0),o.length>2&&\"ID\"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split(\"\").sort(U).join(\"\")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement(\"div\"))}),i(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||o(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||o(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute(\"disabled\")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[\":\"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/,Ce=/^.[^:#\\[\\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if(\"string\"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t<i;t++)if(pe.contains(r[t],this))return!0}));for(t=0;t<i;t++)pe.find(e,r[t],n);return n=this.pushStack(i>1?pe.unique(n):n),n.selector=this.selector?this.selector+\" \"+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,\"string\"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,\"string\"==typeof e){if(r=\"<\"===e.charAt(0)&&\">\"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?\"undefined\"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(pe.contains(this,n[t]))return!0})},closest:function(e,t){for(var n,r=0,i=this.length,o=[],a=we.test(e)||\"string\"!=typeof e?pe(e,t||this.context):0;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,\"parentNode\")},parentsUntil:function(e,t,n){return xe(e,\"parentNode\",n)},next:function(e){return i(e,\"nextSibling\")},prev:function(e){return i(e,\"previousSibling\")},nextAll:function(e){return xe(e,\"nextSibling\")},prevAll:function(e){return xe(e,\"previousSibling\")},nextUntil:function(e,t,n){return xe(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return xe(e,\"previousSibling\",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,\"iframe\")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return\"Until\"!==e.slice(-5)&&(r=n),r&&\"string\"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\\S+/g;pe.Callbacks=function(e){e=\"string\"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u<a.length;)a[u].apply(n[0],n[1])===!1&&e.stopOnFalse&&(u=a.length,n=!1);e.memory||(n=!1),t=!1,i&&(a=n?[]:\"\")},c={add:function(){return a&&(n&&!t&&(u=a.length-1,s.push(n)),function r(t){pe.each(t,function(t,n){pe.isFunction(n)?e.unique&&c.has(n)||a.push(n):n&&n.length&&\"string\"!==pe.type(n)&&r(n)})}(arguments),n&&!t&&l()),this},remove:function(){return pe.each(arguments,function(e,t){for(var n;(n=pe.inArray(t,a,n))>-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n=\"\",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[[\"resolve\",\"done\",pe.Callbacks(\"once memory\"),\"resolved\"],[\"reject\",\"fail\",pe.Callbacks(\"once memory\"),\"rejected\"],[\"notify\",\"progress\",pe.Callbacks(\"memory\")]],n=\"pending\",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+\"With\"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+\"With\"](this===i?r:this,arguments),this},i[o[0]+\"With\"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i<a;i++)o[i]&&pe.isFunction(o[i].promise)?o[i].promise().progress(l(i,n,t)).done(l(i,r,o)).fail(u.reject):--s;return s||u.resolveWith(r,o),u.promise()}});var je;pe.fn.ready=function(e){return pe.ready.promise().done(e),this},pe.extend({isReady:!1,readyWait:1,holdReady:function(e){e?pe.readyWait++:pe.ready(!0)},ready:function(e){(e===!0?--pe.readyWait:pe.isReady)||(pe.isReady=!0,e!==!0&&--pe.readyWait>0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler(\"ready\"),pe(re).off(\"ready\"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),\"complete\"===re.readyState||\"loading\"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener(\"DOMContentLoaded\",s),e.addEventListener(\"load\",s);else{re.attachEvent(\"onreadystatechange\",s),e.attachEvent(\"onload\",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll(\"left\")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst=\"0\"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName(\"body\")[0],n&&n.style&&(t=re.createElement(\"div\"),r=re.createElement(\"div\"),r.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",n.appendChild(r).appendChild(t),\"undefined\"!=typeof t.style.zoom&&(t.style.cssText=\"display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1\",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement(\"div\");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+\" \").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute(\"classid\")===t)},qe=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{\"applet \":!0,\"embed \":!0,\"object \":\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,\"parsedAttrs\"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf(\"data-\")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,\"parsedAttrs\",!0)}return i}return\"object\"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks(\"once memory\").add(function(){pe._removeData(e,t+\"queue\"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return\"string\"!=typeof e&&(t=e,e=\"fx\",n--),arguments.length<n?pe.queue(this[0],e):void 0===t?this:this.each(function(){var n=pe.queue(this,e,t);pe._queueHooks(this,e),\"fx\"===e&&\"inprogress\"!==n[0]&&pe.dequeue(this,e)})},dequeue:function(e){return this.each(function(){pe.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=pe.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};for(\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";a--;)n=pe._data(o[a],e+\"queueHooks\"),n&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}}),function(){var e;fe.shrinkWrapBlocks=function(){if(null!=e)return e;e=!1;var t,n,r;return n=re.getElementsByTagName(\"body\")[0],n&&n.style?(t=re.createElement(\"div\"),r=re.createElement(\"div\"),r.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",n.appendChild(r).appendChild(t),\"undefined\"!=typeof t.style.zoom&&(t.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1\",t.appendChild(re.createElement(\"div\")).style.width=\"5px\",e=3!==t.offsetWidth),n.removeChild(r),e):void 0}}();var Fe=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,Me=new RegExp(\"^(?:([+-])=|)(\"+Fe+\")([a-z%]*)$\",\"i\"),Oe=[\"Top\",\"Right\",\"Bottom\",\"Left\"],Re=function(e,t){return e=t||e,\"none\"===pe.css(e,\"display\")||!pe.contains(e.ownerDocument,e)},Pe=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===pe.type(n)){i=!0;for(s in n)Pe(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,pe.isFunction(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(pe(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},Be=/^(?:checkbox|radio)$/i,We=/<([\\w:-]+)/,Ie=/^$|\\/(?:java|ecma)script/i,$e=/^\\s+/,ze=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video\";!function(){var e=re.createElement(\"div\"),t=re.createDocumentFragment(),n=re.createElement(\"input\");e.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName(\"tbody\").length,fe.htmlSerialize=!!e.getElementsByTagName(\"link\").length,fe.html5Clone=\"<:nav></:nav>\"!==re.createElement(\"nav\").cloneNode(!0).outerHTML,n.type=\"checkbox\",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML=\"<textarea>x</textarea>\",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement(\"input\"),n.setAttribute(\"type\",\"radio\"),n.setAttribute(\"checked\",\"checked\"),n.setAttribute(\"name\",\"t\"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],area:[1,\"<map>\",\"</map>\"],param:[1,\"<object>\",\"</object>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:fe.htmlSerialize?[0,\"\",\"\"]:[1,\"X<div>\",\"</div>\"]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|&#?\\w+;/,Ve=/<tbody/i;!function(){var t,n,r=re.createElement(\"div\");for(t in{submit:!0,change:!0,focusin:!0})n=\"on\"+t,(fe[t]=n in e)||(r.setAttribute(n,\"t\"),fe[t]=r.attributes[n].expando===!1);r=null}();var Ye=/^(?:input|select|textarea)$/i,Je=/^key/,Ge=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ke=/^(?:focusinfocus|focusoutblur)$/,Qe=/^([^.]*)(?:\\.(.+)|)/;pe.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,m=pe._data(e);if(m){for(n.handler&&(u=n,n=u.handler,i=u.selector),n.guid||(n.guid=pe.guid++),(a=m.events)||(a=m.events={}),(c=m.handle)||(c=m.handle=function(e){return\"undefined\"==typeof pe||e&&pe.event.triggered===e.type?void 0:pe.event.dispatch.apply(c.elem,arguments)},c.elem=e),t=(t||\"\").match(De)||[\"\"],s=t.length;s--;)o=Qe.exec(t[s])||[],p=g=o[1],h=(o[2]||\"\").split(\".\").sort(),p&&(l=pe.event.special[p]||{},p=(i?l.delegateType:l.bindType)||p,l=pe.event.special[p]||{},f=pe.extend({type:p,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&pe.expr.match.needsContext.test(i),namespace:h.join(\".\")},u),(d=a[p])||(d=a[p]=[],d.delegateCount=0,l.setup&&l.setup.call(e,r,h,c)!==!1||(e.addEventListener?e.addEventListener(p,c,!1):e.attachEvent&&e.attachEvent(\"on\"+p,c))),l.add&&(l.add.call(e,f),f.handler.guid||(f.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,f):d.push(f),pe.event.global[p]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,m=pe.hasData(e)&&pe._data(e);if(m&&(c=m.events)){for(t=(t||\"\").match(De)||[\"\"],l=t.length;l--;)if(s=Qe.exec(t[l])||[],p=g=s[1],h=(s[2]||\"\").split(\".\").sort(),p){for(f=pe.event.special[p]||{},p=(r?f.delegateType:f.bindType)||p,d=c[p]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),u=o=d.length;o--;)a=d[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&(\"**\"!==r||!a.selector)||(d.splice(o,1),a.selector&&d.delegateCount--,f.remove&&f.remove.call(e,a));u&&!d.length&&(f.teardown&&f.teardown.call(e,h,m.handle)!==!1||pe.removeEvent(e,p,m.handle),delete c[p])}else for(p in c)pe.event.remove(e,p+t[l],n,r,!0);pe.isEmptyObject(c)&&(delete m.handle,pe._removeData(e,\"events\"))}},trigger:function(t,n,r,i){var o,a,s,u,l,c,f,d=[r||re],p=ce.call(t,\"type\")?t.type:t,h=ce.call(t,\"namespace\")?t.namespace.split(\".\"):[];if(s=c=r=r||re,3!==r.nodeType&&8!==r.nodeType&&!Ke.test(p+pe.event.triggered)&&(p.indexOf(\".\")>-1&&(h=p.split(\".\"),p=h.shift(),h.sort()),a=p.indexOf(\":\")<0&&\"on\"+p,t=t[pe.expando]?t:new pe.Event(p,\"object\"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join(\".\"),t.rnamespace=t.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,\"events\")||{})[t.type]&&pe._data(s,\"handle\"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,\"events\")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&(\"click\"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||\"click\"!==e.type)){for(r=[],n=0;n<s;n++)o=t[n],i=o.selector+\" \",void 0===r[i]&&(r[i]=o.needsContext?pe(i,this).index(u)>-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s<t.length&&a.push({elem:this,handlers:t.slice(s)}),a},fix:function(e){if(e[pe.expando])return e;var t,n,r,i=e.type,o=e,a=this.fixHooks[i];for(a||(this.fixHooks[i]=a=Ge.test(i)?this.mouseHooks:Je.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new pe.Event(o),t=r.length;t--;)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||re),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,a.filter?a.filter(e,o):e},props:\"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(e,t){var n,r,i,o=t.button,a=t.fromElement;return null==e.pageX&&null!=t.clientX&&(r=e.target.ownerDocument||re,i=r.documentElement,n=r.body,e.pageX=t.clientX+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0),e.pageY=t.clientY+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?t.toElement:a),e.which||void 0===o||(e.which=1&o?1:2&o?3:4&o?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==b()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:\"focusin\"},blur:{trigger:function(){if(this===b()&&this.blur)return this.blur(),!1},delegateType:\"focusout\"},click:{trigger:function(){if(pe.nodeName(this,\"input\")&&\"checkbox\"===this.type&&this.click)return this.click(),!1},_default:function(e){return pe.nodeName(e.target,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n){var r=pe.extend(new pe.Event,n,{type:e,isSimulated:!0});pe.event.trigger(r,null,t),r.isDefaultPrevented()&&n.preventDefault()}},pe.removeEvent=re.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)}:function(e,t,n){var r=\"on\"+t;e.detachEvent&&(\"undefined\"==typeof e[r]&&(e[r]=null),e.detachEvent(r,n))},pe.Event=function(e,t){return this instanceof pe.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&e.returnValue===!1?v:x):this.type=e,t&&pe.extend(this,t),this.timeStamp=e&&e.timeStamp||pe.now(),void(this[pe.expando]=!0)):new pe.Event(e,t)},pe.Event.prototype={constructor:pe.Event,isDefaultPrevented:x,isPropagationStopped:x,isImmediatePropagationStopped:x,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=v,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=v,e&&!this.isSimulated&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=v,e&&e.stopImmediatePropagation&&e.stopImmediatePropagation(),this.stopPropagation()}},pe.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,t){pe.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return i&&(i===r||pe.contains(r,i))||(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),fe.submit||(pe.event.special.submit={setup:function(){return!pe.nodeName(this,\"form\")&&void pe.event.add(this,\"click._submit keypress._submit\",function(e){var t=e.target,n=pe.nodeName(t,\"input\")||pe.nodeName(t,\"button\")?pe.prop(t,\"form\"):void 0;n&&!pe._data(n,\"submit\")&&(pe.event.add(n,\"submit._submit\",function(e){e._submitBubble=!0}),pe._data(n,\"submit\",!0))})},postDispatch:function(e){e._submitBubble&&(delete e._submitBubble,this.parentNode&&!e.isTrigger&&pe.event.simulate(\"submit\",this.parentNode,e))},teardown:function(){return!pe.nodeName(this,\"form\")&&void pe.event.remove(this,\"._submit\")}}),fe.change||(pe.event.special.change={setup:function(){return Ye.test(this.nodeName)?(\"checkbox\"!==this.type&&\"radio\"!==this.type||(pe.event.add(this,\"propertychange._change\",function(e){\"checked\"===e.originalEvent.propertyName&&(this._justChanged=!0)}),pe.event.add(this,\"click._change\",function(e){this._justChanged&&!e.isTrigger&&(this._justChanged=!1),pe.event.simulate(\"change\",this,e)})),!1):void pe.event.add(this,\"beforeactivate._change\",function(e){var t=e.target;Ye.test(t.nodeName)&&!pe._data(t,\"change\")&&(pe.event.add(t,\"change._change\",function(e){!this.parentNode||e.isSimulated||e.isTrigger||pe.event.simulate(\"change\",this.parentNode,e)}),pe._data(t,\"change\",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||\"radio\"!==t.type&&\"checkbox\"!==t.type)return e.handleObj.handler.apply(this,arguments)},teardown:function(){return pe.event.remove(this,\"._change\"),!Ye.test(this.nodeName)}}),fe.focusin||pe.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){var n=function(e){pe.event.simulate(t,e.target,pe.event.fix(e))};pe.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=pe._data(r,t);i||r.addEventListener(e,n,!0),pe._data(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=pe._data(r,t)-1;i?pe._data(r,t,i):(r.removeEventListener(e,n,!0),pe._removeData(r,t))}}}),pe.fn.extend({on:function(e,t,n,r){return w(this,e,t,n,r)},one:function(e,t,n,r){return w(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,pe(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return t!==!1&&\"function\"!=typeof t||(n=t,t=void 0),n===!1&&(n=x),this.each(function(){pe.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){pe.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return pe.event.trigger(e,t,n,!0)}});var Ze=/ jQuery\\d+=\"(?:null|\\d+)\"/g,et=new RegExp(\"<(?:\"+ze+\")[\\\\s/>]\",\"i\"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,nt=/<script|<style|<link/i,rt=/checked\\s*(?:[^=]|=\\s*.checked.)/i,it=/^true\\/(.*)/,ot=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,at=p(re),st=at.appendChild(re.createElement(\"div\"));pe.extend({htmlPrefilter:function(e){return e.replace(tt,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u=pe.contains(e.ownerDocument,e);if(fe.html5Clone||pe.isXMLDoc(e)||!et.test(\"<\"+e.nodeName+\">\")?o=e.cloneNode(!0):(st.innerHTML=e.outerHTML,st.removeChild(o=st.firstChild)),!(fe.noCloneEvent&&fe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||pe.isXMLDoc(e)))for(r=h(o),s=h(e),a=0;null!=(i=s[a]);++a)r[a]&&k(i,r[a]);if(t)if(n)for(s=s||h(e),r=r||h(o),a=0;null!=(i=s[a]);a++)N(i,r[a]);else N(e,o);return r=h(o,\"script\"),r.length>0&&g(r,!u&&h(e,\"script\")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=pe.expando,u=pe.cache,l=fe.attributes,c=pe.event.special;null!=(n=e[a]);a++)if((t||He(n))&&(i=n[s],o=i&&u[i])){if(o.events)for(r in o.events)c[r]?pe.event.remove(n,r):pe.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||\"undefined\"==typeof n.removeAttribute?n[s]=void 0:n.removeAttribute(s),ne.push(i))}}}),pe.fn.extend({domManip:S,detach:function(e){return A(this,e,!0)},remove:function(e){return A(this,e)},text:function(e){return Pe(this,function(e){return void 0===e?pe.text(this):this.empty().append((this[0]&&this[0].ownerDocument||re).createTextNode(e))},null,e,arguments.length)},append:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.appendChild(e)}})},prepend:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&pe.cleanData(h(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&pe.nodeName(e,\"select\")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return pe.clone(this,e,t)})},html:function(e){return Pe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e)return 1===t.nodeType?t.innerHTML.replace(Ze,\"\"):void 0;if(\"string\"==typeof e&&!nt.test(e)&&(fe.htmlSerialize||!et.test(e))&&(fe.leadingWhitespace||!$e.test(e))&&!Xe[(We.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=pe.htmlPrefilter(e);try{for(;n<r;n++)t=this[n]||{},1===t.nodeType&&(pe.cleanData(h(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=[];return S(this,arguments,function(t){var n=this.parentNode;pe.inArray(this,e)<0&&(pe.cleanData(h(this)),\nn&&n.replaceChild(t,this))},e)}}),pe.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,t){pe.fn[e]=function(e){for(var n,r=0,i=[],o=pe(e),a=o.length-1;r<=a;r++)n=r===a?this:this.clone(!0),pe(o[r])[t](n),ae.apply(i,n.get());return this.pushStack(i)}});var ut,lt={HTML:\"block\",BODY:\"block\"},ct=/^margin/,ft=new RegExp(\"^(\"+Fe+\")(?!px)[a-z%]+$\",\"i\"),dt=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i},pt=re.documentElement;!function(){function t(){var t,c,f=re.documentElement;f.appendChild(u),l.style.cssText=\"-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%\",n=i=s=!1,r=a=!0,e.getComputedStyle&&(c=e.getComputedStyle(l),n=\"1%\"!==(c||{}).top,s=\"2px\"===(c||{}).marginLeft,i=\"4px\"===(c||{width:\"4px\"}).width,l.style.marginRight=\"50%\",r=\"4px\"===(c||{marginRight:\"4px\"}).marginRight,t=l.appendChild(re.createElement(\"div\")),t.style.cssText=l.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0\",t.style.marginRight=t.style.width=\"0\",l.style.width=\"1px\",a=!parseFloat((e.getComputedStyle(t)||{}).marginRight),l.removeChild(t)),l.style.display=\"none\",o=0===l.getClientRects().length,o&&(l.style.display=\"\",l.innerHTML=\"<table><tr><td></td><td>t</td></tr></table>\",t=l.getElementsByTagName(\"td\"),t[0].style.cssText=\"margin:0;border:0;padding:0;display:none\",o=0===t[0].offsetHeight,o&&(t[0].style.display=\"\",t[1].style.display=\"none\",o=0===t[0].offsetHeight)),f.removeChild(u)}var n,r,i,o,a,s,u=re.createElement(\"div\"),l=re.createElement(\"div\");l.style&&(l.style.cssText=\"float:left;opacity:.5\",fe.opacity=\"0.5\"===l.style.opacity,fe.cssFloat=!!l.style.cssFloat,l.style.backgroundClip=\"content-box\",l.cloneNode(!0).style.backgroundClip=\"\",fe.clearCloneStyle=\"content-box\"===l.style.backgroundClip,u=re.createElement(\"div\"),u.style.cssText=\"border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute\",l.innerHTML=\"\",u.appendChild(l),fe.boxSizing=\"\"===l.style.boxSizing||\"\"===l.style.MozBoxSizing||\"\"===l.style.WebkitBoxSizing,pe.extend(fe,{reliableHiddenOffsets:function(){return null==n&&t(),o},boxSizingReliable:function(){return null==n&&t(),i},pixelMarginRight:function(){return null==n&&t(),r},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),a},reliableMarginLeft:function(){return null==n&&t(),s}}))}();var ht,gt,mt=/^(top|right|bottom|left)$/;e.getComputedStyle?(ht=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n.getPropertyValue(t)||n[t]:void 0,\"\"!==a&&void 0!==a||pe.contains(e.ownerDocument,e)||(a=pe.style(e,t)),n&&!fe.pixelMarginRight()&&ft.test(a)&&ct.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o),void 0===a?a:a+\"\"}):pt.currentStyle&&(ht=function(e){return e.currentStyle},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n[t]:void 0,null==a&&s&&s[t]&&(a=s[t]),ft.test(a)&&!mt.test(t)&&(r=s.left,i=e.runtimeStyle,o=i&&i.left,o&&(i.left=e.currentStyle.left),s.left=\"fontSize\"===t?\"1em\":a,a=s.pixelLeft+\"px\",s.left=r,o&&(i.left=o)),void 0===a?a:a+\"\"||\"auto\"});var yt=/alpha\\([^)]*\\)/i,vt=/opacity\\s*=\\s*([^)]*)/i,xt=/^(none|table(?!-c[ea]).+)/,bt=new RegExp(\"^(\"+Fe+\")(.*)$\",\"i\"),wt={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Tt={letterSpacing:\"0\",fontWeight:\"400\"},Ct=[\"Webkit\",\"O\",\"Moz\",\"ms\"],Et=re.createElement(\"div\").style;pe.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=gt(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":fe.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=pe.camelCase(t),u=e.style;if(t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:u[t];if(o=typeof n,\"string\"===o&&(i=Me.exec(n))&&i[1]&&(n=d(e,t,i),o=\"number\"),null!=n&&n===n&&(\"number\"===o&&(n+=i&&i[3]||(pe.cssNumber[s]?\"\":\"px\")),fe.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(u[t]=\"inherit\"),!(a&&\"set\"in a&&void 0===(n=a.set(e,n,r)))))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o,a,s=pe.camelCase(t);return t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],a&&\"get\"in a&&(o=a.get(e,!0,n)),void 0===o&&(o=gt(e,t,r)),\"normal\"===o&&t in Tt&&(o=Tt[t]),\"\"===n||n?(i=parseFloat(o),n===!0||isFinite(i)?i||0:o):o}}),pe.each([\"height\",\"width\"],function(e,t){pe.cssHooks[t]={get:function(e,n,r){if(n)return xt.test(pe.css(e,\"display\"))&&0===e.offsetWidth?dt(e,wt,function(){return M(e,t,r)}):M(e,t,r)},set:function(e,n,r){var i=r&&ht(e);return _(e,n,r?F(e,t,r,fe.boxSizing&&\"border-box\"===pe.css(e,\"boxSizing\",!1,i),i):0)}}}),fe.opacity||(pe.cssHooks.opacity={get:function(e,t){return vt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||\"\")?.01*parseFloat(RegExp.$1)+\"\":t?\"1\":\"\"},set:function(e,t){var n=e.style,r=e.currentStyle,i=pe.isNumeric(t)?\"alpha(opacity=\"+100*t+\")\":\"\",o=r&&r.filter||n.filter||\"\";n.zoom=1,(t>=1||\"\"===t)&&\"\"===pe.trim(o.replace(yt,\"\"))&&n.removeAttribute&&(n.removeAttribute(\"filter\"),\"\"===t||r&&!r.filter)||(n.filter=yt.test(o)?o.replace(yt,i):o+\" \"+i)}}),pe.cssHooks.marginRight=L(fe.reliableMarginRight,function(e,t){if(t)return dt(e,{display:\"inline-block\"},gt,[e,\"marginRight\"])}),pe.cssHooks.marginLeft=L(fe.reliableMarginLeft,function(e,t){if(t)return(parseFloat(gt(e,\"marginLeft\"))||(pe.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-dt(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+\"px\"}),pe.each({margin:\"\",padding:\"\",border:\"Width\"},function(e,t){pe.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o=\"string\"==typeof n?n.split(\" \"):[n];r<4;r++)i[e+Oe[r]+t]=o[r]||o[r-2]||o[0];return i}},ct.test(e)||(pe.cssHooks[e+t].set=_)}),pe.fn.extend({css:function(e,t){return Pe(this,function(e,t,n){var r,i,o={},a=0;if(pe.isArray(t)){for(r=ht(e),i=t.length;a<i;a++)o[t[a]]=pe.css(e,t[a],!1,r);return o}return void 0!==n?pe.style(e,t,n):pe.css(e,t)},e,t,arguments.length>1)},show:function(){return q(this,!0)},hide:function(){return q(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){Re(this)?pe(this).show():pe(this).hide()})}}),pe.Tween=O,O.prototype={constructor:O,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||pe.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(pe.cssNumber[n]?\"\":\"px\")},cur:function(){var e=O.propHooks[this.prop];return e&&e.get?e.get(this):O.propHooks._default.get(this)},run:function(e){var t,n=O.propHooks[this.prop];return this.options.duration?this.pos=t=pe.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):O.propHooks._default.set(this),this}},O.prototype.init.prototype=O.prototype,O.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=pe.css(e.elem,e.prop,\"\"),t&&\"auto\"!==t?t:0)},set:function(e){pe.fx.step[e.prop]?pe.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[pe.cssProps[e.prop]]&&!pe.cssHooks[e.prop]?e.elem[e.prop]=e.now:pe.style(e.elem,e.prop,e.now+e.unit)}}},O.propHooks.scrollTop=O.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},pe.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},pe.fx=O.prototype.init,pe.fx.step={};var Nt,kt,St=/^(?:toggle|show|hide)$/,At=/queueHooks$/;pe.Animation=pe.extend($,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,Me.exec(t),n),n}]},tweener:function(e,t){pe.isFunction(e)?(t=e,e=[\"*\"]):e=e.match(De);for(var n,r=0,i=e.length;r<i;r++)n=e[r],$.tweeners[n]=$.tweeners[n]||[],$.tweeners[n].unshift(t)},prefilters:[W],prefilter:function(e,t){t?$.prefilters.unshift(e):$.prefilters.push(e)}}),pe.speed=function(e,t,n){var r=e&&\"object\"==typeof e?pe.extend({},e):{complete:n||!n&&t||pe.isFunction(e)&&e,duration:e,easing:n&&t||t&&!pe.isFunction(t)&&t};return r.duration=pe.fx.off?0:\"number\"==typeof r.duration?r.duration:r.duration in pe.fx.speeds?pe.fx.speeds[r.duration]:pe.fx.speeds._default,null!=r.queue&&r.queue!==!0||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){pe.isFunction(r.old)&&r.old.call(this),r.queue&&pe.dequeue(this,r.queue)},r},pe.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Re).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=pe.isEmptyObject(e),o=pe.speed(t,n,r),a=function(){var t=$(this,pe.extend({},e),o);(i||pe._data(this,\"finish\"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return\"string\"!=typeof e&&(n=t,t=e,e=void 0),t&&e!==!1&&this.queue(e||\"fx\",[]),this.each(function(){var t=!0,i=null!=e&&e+\"queueHooks\",o=pe.timers,a=pe._data(this);if(i)a[i]&&a[i].stop&&r(a[i]);else for(i in a)a[i]&&a[i].stop&&At.test(i)&&r(a[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||pe.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||\"fx\"),this.each(function(){var t,n=pe._data(this),r=n[e+\"queue\"],i=n[e+\"queueHooks\"],o=pe.timers,a=r?r.length:0;for(n.finish=!0,pe.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),pe.each([\"toggle\",\"show\",\"hide\"],function(e,t){var n=pe.fn[t];pe.fn[t]=function(e,r,i){return null==e||\"boolean\"==typeof e?n.apply(this,arguments):this.animate(P(t,!0),e,r,i)}}),pe.each({slideDown:P(\"show\"),slideUp:P(\"hide\"),slideToggle:P(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,t){pe.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),pe.timers=[],pe.fx.tick=function(){var e,t=pe.timers,n=0;for(Nt=pe.now();n<t.length;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||pe.fx.stop(),Nt=void 0},pe.fx.timer=function(e){pe.timers.push(e),e()?pe.fx.start():pe.timers.pop()},pe.fx.interval=13,pe.fx.start=function(){kt||(kt=e.setInterval(pe.fx.tick,pe.fx.interval))},pe.fx.stop=function(){e.clearInterval(kt),kt=null},pe.fx.speeds={slow:600,fast:200,_default:400},pe.fn.delay=function(t,n){return t=pe.fx?pe.fx.speeds[t]||t:t,n=n||\"fx\",this.queue(n,function(n,r){var i=e.setTimeout(n,t);r.stop=function(){e.clearTimeout(i)}})},function(){var e,t=re.createElement(\"input\"),n=re.createElement(\"div\"),r=re.createElement(\"select\"),i=r.appendChild(re.createElement(\"option\"));n=re.createElement(\"div\"),n.setAttribute(\"className\",\"t\"),n.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",e=n.getElementsByTagName(\"a\")[0],t.setAttribute(\"type\",\"checkbox\"),n.appendChild(t),e=n.getElementsByTagName(\"a\")[0],e.style.cssText=\"top:1px\",fe.getSetAttribute=\"t\"!==n.className,fe.style=/top/.test(e.getAttribute(\"style\")),fe.hrefNormalized=\"/a\"===e.getAttribute(\"href\"),fe.checkOn=!!t.value,fe.optSelected=i.selected,fe.enctype=!!re.createElement(\"form\").enctype,r.disabled=!0,fe.optDisabled=!i.disabled,t=re.createElement(\"input\"),t.setAttribute(\"value\",\"\"),fe.input=\"\"===t.getAttribute(\"value\"),t.value=\"t\",t.setAttribute(\"type\",\"radio\"),fe.radioValue=\"t\"===t.value}();var Dt=/\\r/g,jt=/[\\x20\\t\\r\\n\\f]+/g;pe.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=pe.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,pe(this).val()):e,null==i?i=\"\":\"number\"==typeof i?i+=\"\":pe.isArray(i)&&(i=pe.map(i,function(e){return null==e?\"\":e+\"\"})),t=pe.valHooks[this.type]||pe.valHooks[this.nodeName.toLowerCase()],t&&\"set\"in t&&void 0!==t.set(this,i,\"value\")||(this.value=i))});if(i)return t=pe.valHooks[i.type]||pe.valHooks[i.nodeName.toLowerCase()],t&&\"get\"in t&&void 0!==(n=t.get(i,\"value\"))?n:(n=i.value,\"string\"==typeof n?n.replace(Dt,\"\"):null==n?\"\":n)}}}),pe.extend({valHooks:{option:{get:function(e){var t=pe.find.attr(e,\"value\");return null!=t?t:pe.trim(pe.text(e)).replace(jt,\" \")}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o=\"select-one\"===e.type||i<0,a=o?null:[],s=o?i+1:r.length,u=i<0?s:o?i:0;u<s;u++)if(n=r[u],(n.selected||u===i)&&(fe.optDisabled?!n.disabled:null===n.getAttribute(\"disabled\"))&&(!n.parentNode.disabled||!pe.nodeName(n.parentNode,\"optgroup\"))){if(t=pe(n).val(),o)return t;a.push(t)}return a},set:function(e,t){for(var n,r,i=e.options,o=pe.makeArray(t),a=i.length;a--;)if(r=i[a],pe.inArray(pe.valHooks.option.get(r),o)>-1)try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),pe.each([\"radio\",\"checkbox\"],function(){pe.valHooks[this]={set:function(e,t){if(pe.isArray(t))return e.checked=pe.inArray(pe(e).val(),t)>-1}},fe.checkOn||(pe.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})});var Lt,Ht,qt=pe.expr.attrHandle,_t=/^(?:checked|selected)$/i,Ft=fe.getSetAttribute,Mt=fe.input;pe.fn.extend({attr:function(e,t){return Pe(this,pe.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){pe.removeAttr(this,e)})}}),pe.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?pe.prop(e,t,n):(1===o&&pe.isXMLDoc(e)||(t=t.toLowerCase(),i=pe.attrHooks[t]||(pe.expr.match.bool.test(t)?Ht:Lt)),void 0!==n?null===n?void pe.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:(r=pe.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!fe.radioValue&&\"radio\"===t&&pe.nodeName(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(De);if(o&&1===e.nodeType)for(;n=o[i++];)r=pe.propFix[n]||n,pe.expr.match.bool.test(n)?Mt&&Ft||!_t.test(n)?e[r]=!1:e[pe.camelCase(\"default-\"+n)]=e[r]=!1:pe.attr(e,n,\"\"),e.removeAttribute(Ft?n:r)}}),Ht={set:function(e,t,n){return t===!1?pe.removeAttr(e,n):Mt&&Ft||!_t.test(n)?e.setAttribute(!Ft&&pe.propFix[n]||n,n):e[pe.camelCase(\"default-\"+n)]=e[n]=!0,n}},pe.each(pe.expr.match.bool.source.match(/\\w+/g),function(e,t){var n=qt[t]||pe.find.attr;Mt&&Ft||!_t.test(t)?qt[t]=function(e,t,r){var i,o;return r||(o=qt[t],qt[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,qt[t]=o),i}:qt[t]=function(e,t,n){if(!n)return e[pe.camelCase(\"default-\"+t)]?t.toLowerCase():null}}),Mt&&Ft||(pe.attrHooks.value={set:function(e,t,n){return pe.nodeName(e,\"input\")?void(e.defaultValue=t):Lt&&Lt.set(e,t,n)}}),Ft||(Lt={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+=\"\",\"value\"===n||t===e.getAttribute(n))return t}},qt.id=qt.name=qt.coords=function(e,t,n){var r;if(!n)return(r=e.getAttributeNode(t))&&\"\"!==r.value?r.value:null},pe.valHooks.button={get:function(e,t){var n=e.getAttributeNode(t);if(n&&n.specified)return n.value},set:Lt.set},pe.attrHooks.contenteditable={set:function(e,t,n){Lt.set(e,\"\"!==t&&t,n)}},pe.each([\"width\",\"height\"],function(e,t){pe.attrHooks[t]={set:function(e,n){if(\"\"===n)return e.setAttribute(t,\"auto\"),n}}})),fe.style||(pe.attrHooks.style={get:function(e){return e.style.cssText||void 0},set:function(e,t){return e.style.cssText=t+\"\"}});var Ot=/^(?:input|select|textarea|button|object)$/i,Rt=/^(?:a|area)$/i;pe.fn.extend({prop:function(e,t){return Pe(this,pe.prop,e,t,arguments.length>1)},removeProp:function(e){return e=pe.propFix[e]||e,this.each(function(){try{this[e]=void 0,delete this[e]}catch(t){}})}}),pe.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&pe.isXMLDoc(e)||(t=pe.propFix[t]||t,i=pe.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=pe.find.attr(e,\"tabindex\");return t?parseInt(t,10):Ot.test(e.nodeName)||Rt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),fe.hrefNormalized||pe.each([\"href\",\"src\"],function(e,t){pe.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),fe.optSelected||(pe.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),pe.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){pe.propFix[this.toLowerCase()]=this}),fe.enctype||(pe.propFix.enctype=\"encoding\");var Pt=/[\\t\\r\\n\\f]/g;pe.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).addClass(e.call(this,t,z(this)))});if(\"string\"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(\" \"+i+\" \").replace(Pt,\" \")){for(a=0;o=t[a++];)r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");s=pe.trim(r),i!==s&&pe.attr(n,\"class\",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).removeClass(e.call(this,t,z(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if(\"string\"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(\" \"+i+\" \").replace(Pt,\" \")){for(a=0;o=t[a++];)for(;r.indexOf(\" \"+o+\" \")>-1;)r=r.replace(\" \"+o+\" \",\" \");s=pe.trim(r),i!==s&&pe.attr(n,\"class\",s)}return this},toggleClass:function(e,t){var n=typeof e;return\"boolean\"==typeof t&&\"string\"===n?t?this.addClass(e):this.removeClass(e):pe.isFunction(e)?this.each(function(n){pe(this).toggleClass(e.call(this,n,z(this),t),t)}):this.each(function(){var t,r,i,o;if(\"string\"===n)for(r=0,i=pe(this),o=e.match(De)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&\"boolean\"!==n||(t=z(this),t&&pe._data(this,\"__className__\",t),pe.attr(this,\"class\",t||e===!1?\"\":pe._data(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;for(t=\" \"+e+\" \";n=this[r++];)if(1===n.nodeType&&(\" \"+z(n)+\" \").replace(Pt,\" \").indexOf(t)>-1)return!0;return!1}}),pe.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(e,t){pe.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),pe.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var Bt=e.location,Wt=pe.now(),It=/\\?/,$t=/(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g;pe.parseJSON=function(t){if(e.JSON&&e.JSON.parse)return e.JSON.parse(t+\"\");var n,r=null,i=pe.trim(t+\"\");return i&&!pe.trim(i.replace($t,function(e,t,i,o){return n&&t&&(r=0),0===r?e:(n=i||t,r+=!o-!i,\"\")}))?Function(\"return \"+i)():pe.error(\"Invalid JSON: \"+t)},pe.parseXML=function(t){var n,r;if(!t||\"string\"!=typeof t)return null;try{e.DOMParser?(r=new e.DOMParser,n=r.parseFromString(t,\"text/xml\")):(n=new e.ActiveXObject(\"Microsoft.XMLDOM\"),n.async=\"false\",n.loadXML(t))}catch(i){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName(\"parsererror\").length||pe.error(\"Invalid XML: \"+t),n};var zt=/#.*$/,Xt=/([?&])_=[^&]*/,Ut=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/gm,Vt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Yt=/^(?:GET|HEAD)$/,Jt=/^\\/\\//,Gt=/^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,Kt={},Qt={},Zt=\"*/\".concat(\"*\"),en=Bt.href,tn=Gt.exec(en.toLowerCase())||[];pe.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:en,type:\"GET\",isLocal:Vt.test(tn[1]),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Zt,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":pe.parseJSON,\"text xml\":pe.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?V(V(e,pe.ajaxSettings),t):V(pe.ajaxSettings,e)},ajaxPrefilter:X(Kt),ajaxTransport:X(Qt),ajax:function(t,n){function r(t,n,r,i){var o,f,v,x,w,C=n;2!==b&&(b=2,u&&e.clearTimeout(u),c=void 0,s=i||\"\",T.readyState=t>0?4:0,o=t>=200&&t<300||304===t,r&&(x=Y(d,T,r)),x=J(d,x,T,o),o?(d.ifModified&&(w=T.getResponseHeader(\"Last-Modified\"),w&&(pe.lastModified[a]=w),w=T.getResponseHeader(\"etag\"),w&&(pe.etag[a]=w)),204===t||\"HEAD\"===d.type?C=\"nocontent\":304===t?C=\"notmodified\":(C=x.state,f=x.data,v=x.error,o=!v)):(v=C,!t&&C||(C=\"error\",t<0&&(t=0))),T.status=t,T.statusText=(n||C)+\"\",o?g.resolveWith(p,[f,C,T]):g.rejectWith(p,[T,C,v]),T.statusCode(y),y=void 0,l&&h.trigger(o?\"ajaxSuccess\":\"ajaxError\",[T,d,o?f:v]),m.fireWith(p,[T,C]),l&&(h.trigger(\"ajaxComplete\",[T,d]),--pe.active||pe.event.trigger(\"ajaxStop\")))}\"object\"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,d=pe.ajaxSetup({},n),p=d.context||d,h=d.context&&(p.nodeType||p.jquery)?pe(p):pe.event,g=pe.Deferred(),m=pe.Callbacks(\"once memory\"),y=d.statusCode||{},v={},x={},b=0,w=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!f)for(f={};t=Ut.exec(s);)f[t[1].toLowerCase()]=t[2];t=f[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?s:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=x[n]=x[n]||e,v[e]=t),this},overrideMimeType:function(e){return b||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)y[t]=[y[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||w;return c&&c.abort(t),r(0,t),this}};if(g.promise(T).complete=m.add,T.success=T.done,T.error=T.fail,d.url=((t||d.url||en)+\"\").replace(zt,\"\").replace(Jt,tn[1]+\"//\"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=pe.trim(d.dataType||\"*\").toLowerCase().match(De)||[\"\"],null==d.crossDomain&&(i=Gt.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===tn[1]&&i[2]===tn[2]&&(i[3]||(\"http:\"===i[1]?\"80\":\"443\"))===(tn[3]||(\"http:\"===tn[1]?\"80\":\"443\")))),d.data&&d.processData&&\"string\"!=typeof d.data&&(d.data=pe.param(d.data,d.traditional)),U(Kt,d,n,T),2===b)return T;l=pe.event&&d.global,l&&0===pe.active++&&pe.event.trigger(\"ajaxStart\"),d.type=d.type.toUpperCase(),d.hasContent=!Yt.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(It.test(a)?\"&\":\"?\")+d.data,delete d.data),d.cache===!1&&(d.url=Xt.test(a)?a.replace(Xt,\"$1_=\"+Wt++):a+(It.test(a)?\"&\":\"?\")+\"_=\"+Wt++)),d.ifModified&&(pe.lastModified[a]&&T.setRequestHeader(\"If-Modified-Since\",pe.lastModified[a]),pe.etag[a]&&T.setRequestHeader(\"If-None-Match\",pe.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&T.setRequestHeader(\"Content-Type\",d.contentType),T.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(\"*\"!==d.dataTypes[0]?\", \"+Zt+\"; q=0.01\":\"\"):d.accepts[\"*\"]);for(o in d.headers)T.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(p,T,d)===!1||2===b))return T.abort();w=\"abort\";for(o in{success:1,error:1,complete:1})T[o](d[o]);if(c=U(Qt,d,n,T)){if(T.readyState=1,l&&h.trigger(\"ajaxSend\",[T,d]),2===b)return T;d.async&&d.timeout>0&&(u=e.setTimeout(function(){T.abort(\"timeout\")},d.timeout));try{b=1,c.send(v,r)}catch(C){if(!(b<2))throw C;r(-1,C)}}else r(-1,\"No Transport\");return T},getJSON:function(e,t,n){return pe.get(e,t,n,\"json\")},getScript:function(e,t){return pe.get(e,void 0,t,\"script\")}}),pe.each([\"get\",\"post\"],function(e,t){pe[t]=function(e,n,r,i){return pe.isFunction(n)&&(i=i||r,r=n,n=void 0),pe.ajax(pe.extend({url:e,type:t,dataType:i,data:n,success:r},pe.isPlainObject(e)&&e))}}),pe._evalUrl=function(e){return pe.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,\"throws\":!0})},pe.fn.extend({wrapAll:function(e){if(pe.isFunction(e))return this.each(function(t){pe(this).wrapAll(e.call(this,t))});if(this[0]){var t=pe(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return pe.isFunction(e)?this.each(function(t){pe(this).wrapInner(e.call(this,t))}):this.each(function(){var t=pe(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=pe.isFunction(e);return this.each(function(n){pe(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){pe.nodeName(this,\"body\")||pe(this).replaceWith(this.childNodes)}).end()}}),pe.expr.filters.hidden=function(e){return fe.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:K(e)},pe.expr.filters.visible=function(e){return!pe.expr.filters.hidden(e)};var nn=/%20/g,rn=/\\[\\]$/,on=/\\r?\\n/g,an=/^(?:submit|button|image|reset|file)$/i,sn=/^(?:input|select|textarea|keygen)/i;pe.param=function(e,t){var n,r=[],i=function(e,t){t=pe.isFunction(t)?t():null==t?\"\":t,r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(t)};if(void 0===t&&(t=pe.ajaxSettings&&pe.ajaxSettings.traditional),pe.isArray(e)||e.jquery&&!pe.isPlainObject(e))pe.each(e,function(){i(this.name,this.value)});else for(n in e)Q(n,e[n],t,i);return r.join(\"&\").replace(nn,\"+\")},pe.fn.extend({serialize:function(){return pe.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=pe.prop(this,\"elements\");return e?pe.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!pe(this).is(\":disabled\")&&sn.test(this.nodeName)&&!an.test(e)&&(this.checked||!Be.test(e))}).map(function(e,t){var n=pe(this).val();return null==n?null:pe.isArray(n)?pe.map(n,function(e){return{name:t.name,value:e.replace(on,\"\\r\\n\")}}):{name:t.name,value:n.replace(on,\"\\r\\n\")}}).get()}}),pe.ajaxSettings.xhr=void 0!==e.ActiveXObject?function(){return this.isLocal?ee():re.documentMode>8?Z():/^(get|post|head|put|delete|options)$/i.test(this.type)&&Z()||ee()}:Z;var un=0,ln={},cn=pe.ajaxSettings.xhr();e.attachEvent&&e.attachEvent(\"onunload\",function(){for(var e in ln)ln[e](void 0,!0)}),fe.cors=!!cn&&\"withCredentials\"in cn,cn=fe.ajax=!!cn,cn&&pe.ajaxTransport(function(t){if(!t.crossDomain||fe.cors){var n;return{send:function(r,i){var o,a=t.xhr(),s=++un;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||r[\"X-Requested-With\"]||(r[\"X-Requested-With\"]=\"XMLHttpRequest\");for(o in r)void 0!==r[o]&&a.setRequestHeader(o,r[o]+\"\");a.send(t.hasContent&&t.data||null),n=function(e,r){var o,u,l;if(n&&(r||4===a.readyState))if(delete ln[s],n=void 0,a.onreadystatechange=pe.noop,r)4!==a.readyState&&a.abort();else{l={},o=a.status,\"string\"==typeof a.responseText&&(l.text=a.responseText);try{u=a.statusText}catch(c){u=\"\"}o||!t.isLocal||t.crossDomain?1223===o&&(o=204):o=l.text?200:404}l&&i(o,u,l,a.getAllResponseHeaders())},t.async?4===a.readyState?e.setTimeout(n):a.onreadystatechange=ln[s]=n:n()},abort:function(){n&&n(void 0,!0)}}}}),pe.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return pe.globalEval(e),e}}}),pe.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\",e.global=!1)}),pe.ajaxTransport(\"script\",function(e){if(e.crossDomain){var t,n=re.head||pe(\"head\")[0]||re.documentElement;return{send:function(r,i){t=re.createElement(\"script\"),t.async=!0,e.scriptCharset&&(t.charset=e.scriptCharset),t.src=e.url,t.onload=t.onreadystatechange=function(e,n){(n||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),t=null,n||i(200,\"success\"))},n.insertBefore(t,n.firstChild)},abort:function(){t&&t.onload(void 0,!0)}}}});var fn=[],dn=/(=)\\?(?=&|$)|\\?\\?/;pe.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=fn.pop()||pe.expando+\"_\"+Wt++;return this[e]=!0,e}}),pe.ajaxPrefilter(\"json jsonp\",function(t,n,r){var i,o,a,s=t.jsonp!==!1&&(dn.test(t.url)?\"url\":\"string\"==typeof t.data&&0===(t.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&dn.test(t.data)&&\"data\");if(s||\"jsonp\"===t.dataTypes[0])return i=t.jsonpCallback=pe.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(dn,\"$1\"+i):t.jsonp!==!1&&(t.url+=(It.test(t.url)?\"&\":\"?\")+t.jsonp+\"=\"+i),t.converters[\"script json\"]=function(){return a||pe.error(i+\" was not called\"),a[0]},t.dataTypes[0]=\"json\",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?pe(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,fn.push(i)),a&&pe.isFunction(o)&&o(a[0]),a=o=void 0}),\"script\"}),pe.parseHTML=function(e,t,n){if(!e||\"string\"!=typeof e)return null;\"boolean\"==typeof t&&(n=t,t=!1),t=t||re;var r=Te.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=y([e],t,i),i&&i.length&&pe(i).remove(),pe.merge([],r.childNodes))};var pn=pe.fn.load;return pe.fn.load=function(e,t,n){if(\"string\"!=typeof e&&pn)return pn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(\" \");return s>-1&&(r=pe.trim(e.slice(s,e.length)),e=e.slice(0,s)),pe.isFunction(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),a.length>0&&pe.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?pe(\"<div>\").append(pe.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},pe.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){pe.fn[t]=function(e){return this.on(t,e)}}),pe.expr.filters.animated=function(e){return pe.grep(pe.timers,function(t){return e===t.elem}).length},pe.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=pe.css(e,\"position\"),f=pe(e),d={};\"static\"===c&&(e.style.position=\"relative\"),s=f.offset(),o=pe.css(e,\"top\"),u=pe.css(e,\"left\"),l=(\"absolute\"===c||\"fixed\"===c)&&pe.inArray(\"auto\",[o,u])>-1,l?(r=f.position(),a=r.top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),pe.isFunction(t)&&(t=t.call(e,n,pe.extend({},s))),null!=t.top&&(d.top=t.top-s.top+a),null!=t.left&&(d.left=t.left-s.left+i),\"using\"in t?t.using.call(e,d):f.css(d)}},pe.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){pe.offset.setOffset(this,e,t)});var t,n,r={top:0,left:0},i=this[0],o=i&&i.ownerDocument;if(o)return t=o.documentElement,pe.contains(t,i)?(\"undefined\"!=typeof i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=te(o),{top:r.top+(n.pageYOffset||t.scrollTop)-(t.clientTop||0),left:r.left+(n.pageXOffset||t.scrollLeft)-(t.clientLeft||0)}):r},position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return\"fixed\"===pe.css(r,\"position\")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),pe.nodeName(e[0],\"html\")||(n=e.offset()),n.top+=pe.css(e[0],\"borderTopWidth\",!0),n.left+=pe.css(e[0],\"borderLeftWidth\",!0)),{top:t.top-n.top-pe.css(r,\"marginTop\",!0),left:t.left-n.left-pe.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){\nfor(var e=this.offsetParent;e&&!pe.nodeName(e,\"html\")&&\"static\"===pe.css(e,\"position\");)e=e.offsetParent;return e||pt})}}),pe.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(e,t){var n=/Y/.test(t);pe.fn[e]=function(r){return Pe(this,function(e,r,i){var o=te(e);return void 0===i?o?t in o?o[t]:o.document.documentElement[r]:e[r]:void(o?o.scrollTo(n?pe(o).scrollLeft():i,n?i:pe(o).scrollTop()):e[r]=i)},e,r,arguments.length,null)}}),pe.each([\"top\",\"left\"],function(e,t){pe.cssHooks[t]=L(fe.pixelPosition,function(e,n){if(n)return n=gt(e,t),ft.test(n)?pe(e).position()[t]+\"px\":n})}),pe.each({Height:\"height\",Width:\"width\"},function(e,t){pe.each({padding:\"inner\"+e,content:t,\"\":\"outer\"+e},function(n,r){pe.fn[r]=function(r,i){var o=arguments.length&&(n||\"boolean\"!=typeof r),a=n||(r===!0||i===!0?\"margin\":\"border\");return Pe(this,function(t,n,r){var i;return pe.isWindow(t)?t.document.documentElement[\"client\"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body[\"scroll\"+e],i[\"scroll\"+e],t.body[\"offset\"+e],i[\"offset\"+e],i[\"client\"+e])):void 0===r?pe.css(t,n,a):pe.style(t,n,r,a)},t,o?r:void 0,o,null)}})}),pe.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),pe.fn.size=function(){return this.length},pe.fn.andSelf=pe.fn.addBack,layui.define(function(e){layui.$=pe,e(\"jquery\",pe)}),pe});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/laydate.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;!function(){\"use strict\";var e=window.layui&&layui.define,t={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,n=t.length-1,a=n;a>0;a--)if(\"interactive\"===t[a].readyState){e=t[a].src;break}return e||t[n].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),getStyle:function(e,t){var n=e.currentStyle?e.currentStyle:window.getComputedStyle(e,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](t)},link:function(e,a,i){if(n.path){var r=document.getElementsByTagName(\"head\")[0],o=document.createElement(\"link\");\"string\"==typeof a&&(i=a);var s=(i||e).replace(/\\.|\\//g,\"\"),l=\"layuicss-\"+s,d=0;o.rel=\"stylesheet\",o.href=n.path+e,o.id=l,document.getElementById(l)||r.appendChild(o),\"function\"==typeof a&&!function c(){return++d>80?window.console&&console.error(\"laydate.css: Invalid\"):void(1989===parseInt(t.getStyle(document.getElementById(l),\"width\"))?a():setTimeout(c,100))}()}}},n={v:\"5.0.9\",config:{},index:window.laydate&&window.laydate.v?1e5:0,path:t.getPath,set:function(e){var t=this;return t.config=w.extend({},t.config,e),t},ready:function(a){var i=\"laydate\",r=\"\",o=(e?\"modules/laydate/\":\"theme/\")+\"default/laydate.css?v=\"+n.v+r;return e?layui.addcss(o,a,i):t.link(o,a,i),this}},a=function(){var e=this;return{hint:function(t){e.hint.call(e,t)},config:e.config}},i=\"laydate\",r=\".layui-laydate\",o=\"layui-this\",s=\"laydate-disabled\",l=\"开始日期超出了结束日期<br>建议重新选择\",d=[100,2e5],c=\"layui-laydate-static\",m=\"layui-laydate-list\",u=\"laydate-selected\",h=\"layui-laydate-hint\",y=\"laydate-day-prev\",f=\"laydate-day-next\",p=\"layui-laydate-footer\",g=\".laydate-btns-confirm\",v=\"laydate-time-text\",D=\".laydate-btns-time\",T=function(e){var t=this;t.index=++n.index,t.config=w.extend({},t.config,n.config,e),n.ready(function(){t.init()})},w=function(e){return new C(e)},C=function(e){for(var t=0,n=\"object\"==typeof e?[e]:(this.selector=e,document.querySelectorAll(e||null));t<n.length;t++)this.push(n[t])};C.prototype=[],C.prototype.constructor=C,w.extend=function(){var e=1,t=arguments,n=function(e,t){e=e||(t.constructor===Array?[]:{});for(var a in t)e[a]=t[a]&&t[a].constructor===Object?n(e[a],t[a]):t[a];return e};for(t[0]=\"object\"==typeof t[0]?t[0]:{};e<t.length;e++)\"object\"==typeof t[e]&&n(t[0],t[e]);return t[0]},w.ie=function(){var e=navigator.userAgent.toLowerCase();return!!(window.ActiveXObject||\"ActiveXObject\"in window)&&((e.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),w.stope=function(e){e=e||window.event,e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},w.each=function(e,t){var n,a=this;if(\"function\"!=typeof t)return a;if(e=e||[],e.constructor===Object){for(n in e)if(t.call(e[n],n,e[n]))break}else for(n=0;n<e.length&&!t.call(e[n],n,e[n]);n++);return a},w.digit=function(e,t,n){var a=\"\";e=String(e),t=t||2;for(var i=e.length;i<t;i++)a+=\"0\";return e<Math.pow(10,t)?a+(0|e):e},w.elem=function(e,t){var n=document.createElement(e);return w.each(t||{},function(e,t){n.setAttribute(e,t)}),n},C.addStr=function(e,t){return e=e.replace(/\\s+/,\" \"),t=t.replace(/\\s+/,\" \").split(\" \"),w.each(t,function(t,n){new RegExp(\"\\\\b\"+n+\"\\\\b\").test(e)||(e=e+\" \"+n)}),e.replace(/^\\s|\\s$/,\"\")},C.removeStr=function(e,t){return e=e.replace(/\\s+/,\" \"),t=t.replace(/\\s+/,\" \").split(\" \"),w.each(t,function(t,n){var a=new RegExp(\"\\\\b\"+n+\"\\\\b\");a.test(e)&&(e=e.replace(a,\"\"))}),e.replace(/\\s+/,\" \").replace(/^\\s|\\s$/,\"\")},C.prototype.find=function(e){var t=this,n=0,a=[],i=\"object\"==typeof e;return this.each(function(r,o){for(var s=i?[e]:o.querySelectorAll(e||null);n<s.length;n++)a.push(s[n]);t.shift()}),i||(t.selector=(t.selector?t.selector+\" \":\"\")+e),w.each(a,function(e,n){t.push(n)}),t},C.prototype.each=function(e){return w.each.call(this,this,e)},C.prototype.addClass=function(e,t){return this.each(function(n,a){a.className=C[t?\"removeStr\":\"addStr\"](a.className,e)})},C.prototype.removeClass=function(e){return this.addClass(e,!0)},C.prototype.hasClass=function(e){var t=!1;return this.each(function(n,a){new RegExp(\"\\\\b\"+e+\"\\\\b\").test(a.className)&&(t=!0)}),t},C.prototype.attr=function(e,t){var n=this;return void 0===t?function(){if(n.length>0)return n[0].getAttribute(e)}():n.each(function(n,a){a.setAttribute(e,t)})},C.prototype.removeAttr=function(e){return this.each(function(t,n){n.removeAttribute(e)})},C.prototype.html=function(e){return this.each(function(t,n){n.innerHTML=e})},C.prototype.val=function(e){return this.each(function(t,n){n.value=e})},C.prototype.append=function(e){return this.each(function(t,n){\"object\"==typeof e?n.appendChild(e):n.innerHTML=n.innerHTML+e})},C.prototype.remove=function(e){return this.each(function(t,n){e?n.removeChild(e):n.parentNode.removeChild(n)})},C.prototype.on=function(e,t){return this.each(function(n,a){a.attachEvent?a.attachEvent(\"on\"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1)})},C.prototype.off=function(e,t){return this.each(function(n,a){a.detachEvent?a.detachEvent(\"on\"+e,t):a.removeEventListener(e,t,!1)})},T.isLeapYear=function(e){return e%4===0&&e%100!==0||e%400===0},T.prototype.config={type:\"date\",range:!1,format:\"yyyy-MM-dd\",value:null,isInitValue:!0,min:\"1900-1-1\",max:\"2099-12-31\",trigger:\"focus\",show:!1,showBottom:!0,btns:[\"clear\",\"now\",\"confirm\"],lang:\"cn\",theme:\"default\",position:null,calendar:!1,mark:{},zIndex:null,done:null,change:null},T.prototype.lang=function(){var e=this,t=e.config,n={cn:{weeks:[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],time:[\"时\",\"分\",\"秒\"],timeTips:\"选择时间\",startTime:\"开始时间\",endTime:\"结束时间\",dateTips:\"返回日期\",month:[\"一\",\"二\",\"三\",\"四\",\"五\",\"六\",\"七\",\"八\",\"九\",\"十\",\"十一\",\"十二\"],tools:{confirm:\"确定\",clear:\"清空\",now:\"现在\"}},en:{weeks:[\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"],time:[\"Hours\",\"Minutes\",\"Seconds\"],timeTips:\"Select Time\",startTime:\"Start Time\",endTime:\"End Time\",dateTips:\"Select Date\",month:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],tools:{confirm:\"Confirm\",clear:\"Clear\",now:\"Now\"}}};return n[t.lang]||n.cn},T.prototype.init=function(){var e=this,t=e.config,n=\"yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s\",a=\"static\"===t.position,i={year:\"yyyy\",month:\"yyyy-MM\",date:\"yyyy-MM-dd\",time:\"HH:mm:ss\",datetime:\"yyyy-MM-dd HH:mm:ss\"};t.elem=w(t.elem),t.eventElem=w(t.eventElem),t.elem[0]&&(t.range===!0&&(t.range=\"-\"),t.format===i.date&&(t.format=i[t.type]),e.format=t.format.match(new RegExp(n+\"|.\",\"g\"))||[],e.EXP_IF=\"\",e.EXP_SPLIT=\"\",w.each(e.format,function(t,a){var i=new RegExp(n).test(a)?\"\\\\d{\"+function(){return new RegExp(n).test(e.format[0===t?t+1:t-1]||\"\")?/^yyyy|y$/.test(a)?4:a.length:/^yyyy$/.test(a)?\"1,4\":/^y$/.test(a)?\"1,308\":\"1,2\"}()+\"}\":\"\\\\\"+a;e.EXP_IF=e.EXP_IF+i,e.EXP_SPLIT=e.EXP_SPLIT+\"(\"+i+\")\"}),e.EXP_IF=new RegExp(\"^\"+(t.range?e.EXP_IF+\"\\\\s\\\\\"+t.range+\"\\\\s\"+e.EXP_IF:e.EXP_IF)+\"$\"),e.EXP_SPLIT=new RegExp(\"^\"+e.EXP_SPLIT+\"$\",\"\"),e.isInput(t.elem[0])||\"focus\"===t.trigger&&(t.trigger=\"click\"),t.elem.attr(\"lay-key\")||(t.elem.attr(\"lay-key\",e.index),t.eventElem.attr(\"lay-key\",e.index)),t.mark=w.extend({},t.calendar&&\"cn\"===t.lang?{\"0-1-1\":\"元旦\",\"0-2-14\":\"情人\",\"0-3-8\":\"妇女\",\"0-3-12\":\"植树\",\"0-4-1\":\"愚人\",\"0-5-1\":\"劳动\",\"0-5-4\":\"青年\",\"0-6-1\":\"儿童\",\"0-9-10\":\"教师\",\"0-9-18\":\"国耻\",\"0-10-1\":\"国庆\",\"0-12-25\":\"圣诞\"}:{},t.mark),w.each([\"min\",\"max\"],function(e,n){var a=[],i=[];if(\"number\"==typeof t[n]){var r=t[n],o=(new Date).getTime(),s=864e5,l=new Date(r?r<s?o+r*s:r:o);a=[l.getFullYear(),l.getMonth()+1,l.getDate()],r<s||(i=[l.getHours(),l.getMinutes(),l.getSeconds()])}else a=(t[n].match(/\\d+-\\d+-\\d+/)||[\"\"])[0].split(\"-\"),i=(t[n].match(/\\d+:\\d+:\\d+/)||[\"\"])[0].split(\":\");t[n]={year:0|a[0]||(new Date).getFullYear(),month:a[1]?(0|a[1])-1:(new Date).getMonth(),date:0|a[2]||(new Date).getDate(),hours:0|i[0],minutes:0|i[1],seconds:0|i[2]}}),e.elemID=\"layui-laydate\"+t.elem.attr(\"lay-key\"),(t.show||a)&&e.render(),a||e.events(),t.value&&t.isInitValue&&(t.value.constructor===Date?e.setValue(e.parse(0,e.systemDate(t.value))):e.setValue(t.value)))},T.prototype.render=function(){var e=this,t=e.config,n=e.lang(),a=\"static\"===t.position,i=e.elem=w.elem(\"div\",{id:e.elemID,\"class\":[\"layui-laydate\",t.range?\" layui-laydate-range\":\"\",a?\" \"+c:\"\",t.theme&&\"default\"!==t.theme&&!/^#/.test(t.theme)?\" laydate-theme-\"+t.theme:\"\"].join(\"\")}),r=e.elemMain=[],o=e.elemHeader=[],s=e.elemCont=[],l=e.table=[],d=e.footer=w.elem(\"div\",{\"class\":p});if(t.zIndex&&(i.style.zIndex=t.zIndex),w.each(new Array(2),function(e){if(!t.range&&e>0)return!0;var a=w.elem(\"div\",{\"class\":\"layui-laydate-header\"}),i=[function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-y\"});return e.innerHTML=\"&#xe65a;\",e}(),function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-m\"});return e.innerHTML=\"&#xe603;\",e}(),function(){var e=w.elem(\"div\",{\"class\":\"laydate-set-ym\"}),t=w.elem(\"span\"),n=w.elem(\"span\");return e.appendChild(t),e.appendChild(n),e}(),function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-m\"});return e.innerHTML=\"&#xe602;\",e}(),function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-y\"});return e.innerHTML=\"&#xe65b;\",e}()],d=w.elem(\"div\",{\"class\":\"layui-laydate-content\"}),c=w.elem(\"table\"),m=w.elem(\"thead\"),u=w.elem(\"tr\");w.each(i,function(e,t){a.appendChild(t)}),m.appendChild(u),w.each(new Array(6),function(e){var t=c.insertRow(0);w.each(new Array(7),function(a){if(0===e){var i=w.elem(\"th\");i.innerHTML=n.weeks[a],u.appendChild(i)}t.insertCell(a)})}),c.insertBefore(m,c.children[0]),d.appendChild(c),r[e]=w.elem(\"div\",{\"class\":\"layui-laydate-main laydate-main-list-\"+e}),r[e].appendChild(a),r[e].appendChild(d),o.push(i),s.push(d),l.push(c)}),w(d).html(function(){var e=[],i=[];return\"datetime\"===t.type&&e.push('<span lay-type=\"datetime\" class=\"laydate-btns-time\">'+n.timeTips+\"</span>\"),w.each(t.btns,function(e,r){var o=n.tools[r]||\"btn\";t.range&&\"now\"===r||(a&&\"clear\"===r&&(o=\"cn\"===t.lang?\"重置\":\"Reset\"),i.push('<span lay-type=\"'+r+'\" class=\"laydate-btns-'+r+'\">'+o+\"</span>\"))}),e.push('<div class=\"laydate-footer-btns\">'+i.join(\"\")+\"</div>\"),e.join(\"\")}()),w.each(r,function(e,t){i.appendChild(t)}),t.showBottom&&i.appendChild(d),/^#/.test(t.theme)){var m=w.elem(\"style\"),u=[\"#{{id}} .layui-laydate-header{background-color:{{theme}};}\",\"#{{id}} .layui-this{background-color:{{theme}} !important;}\"].join(\"\").replace(/{{id}}/g,e.elemID).replace(/{{theme}}/g,t.theme);\"styleSheet\"in m?(m.setAttribute(\"type\",\"text/css\"),m.styleSheet.cssText=u):m.innerHTML=u,w(i).addClass(\"laydate-theme-molv\"),i.appendChild(m)}e.remove(T.thisElemDate),a?t.elem.append(i):(document.body.appendChild(i),e.position()),e.checkDate().calendar(),e.changeEvent(),T.thisElemDate=e.elemID,\"function\"==typeof t.ready&&t.ready(w.extend({},t.dateTime,{month:t.dateTime.month+1}))},T.prototype.remove=function(e){var t=this,n=(t.config,w(\"#\"+(e||t.elemID)));return n.hasClass(c)||t.checkDate(function(){n.remove()}),t},T.prototype.position=function(){var e=this,t=e.config,n=e.bindElem||t.elem[0],a=n.getBoundingClientRect(),i=e.elem.offsetWidth,r=e.elem.offsetHeight,o=function(e){return e=e?\"scrollLeft\":\"scrollTop\",document.body[e]|document.documentElement[e]},s=function(e){return document.documentElement[e?\"clientWidth\":\"clientHeight\"]},l=5,d=a.left,c=a.bottom;d+i+l>s(\"width\")&&(d=s(\"width\")-i-l),c+r+l>s()&&(c=a.top>r?a.top-r:s()-r,c-=2*l),t.position&&(e.elem.style.position=t.position),e.elem.style.left=d+(\"fixed\"===t.position?0:o(1))+\"px\",e.elem.style.top=c+(\"fixed\"===t.position?0:o())+\"px\"},T.prototype.hint=function(e){var t=this,n=(t.config,w.elem(\"div\",{\"class\":h}));t.elem&&(n.innerHTML=e||\"\",w(t.elem).find(\".\"+h).remove(),t.elem.appendChild(n),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){w(t.elem).find(\".\"+h).remove()},3e3))},T.prototype.getAsYM=function(e,t,n){return n?t--:t++,t<0&&(t=11,e--),t>11&&(t=0,e++),[e,t]},T.prototype.systemDate=function(e){var t=e||new Date;return{year:t.getFullYear(),month:t.getMonth(),date:t.getDate(),hours:e?e.getHours():0,minutes:e?e.getMinutes():0,seconds:e?e.getSeconds():0}},T.prototype.checkDate=function(e){var t,a,i=this,r=(new Date,i.config),o=r.dateTime=r.dateTime||i.systemDate(),s=i.bindElem||r.elem[0],l=(i.isInput(s)?\"val\":\"html\",i.isInput(s)?s.value:\"static\"===r.position?\"\":s.innerHTML),c=function(e){e.year>d[1]&&(e.year=d[1],a=!0),e.month>11&&(e.month=11,a=!0),e.hours>23&&(e.hours=0,a=!0),e.minutes>59&&(e.minutes=0,e.hours++,a=!0),e.seconds>59&&(e.seconds=0,e.minutes++,a=!0),t=n.getEndDate(e.month+1,e.year),e.date>t&&(e.date=t,a=!0)},m=function(e,t,n){var o=[\"startTime\",\"endTime\"];t=(t.match(i.EXP_SPLIT)||[]).slice(1),n=n||0,r.range&&(i[o[n]]=i[o[n]]||{}),w.each(i.format,function(s,l){var c=parseFloat(t[s]);t[s].length<l.length&&(a=!0),/yyyy|y/.test(l)?(c<d[0]&&(c=d[0],a=!0),e.year=c):/MM|M/.test(l)?(c<1&&(c=1,a=!0),e.month=c-1):/dd|d/.test(l)?(c<1&&(c=1,a=!0),e.date=c):/HH|H/.test(l)?(c<1&&(c=0,a=!0),e.hours=c,r.range&&(i[o[n]].hours=c)):/mm|m/.test(l)?(c<1&&(c=0,a=!0),e.minutes=c,r.range&&(i[o[n]].minutes=c)):/ss|s/.test(l)&&(c<1&&(c=0,a=!0),e.seconds=c,r.range&&(i[o[n]].seconds=c))}),c(e)};return\"limit\"===e?(c(o),i):(l=l||r.value,\"string\"==typeof l&&(l=l.replace(/\\s+/g,\" \").replace(/^\\s|\\s$/g,\"\")),i.startState&&!i.endState&&(delete i.startState,i.endState=!0),\"string\"==typeof l&&l?i.EXP_IF.test(l)?r.range?(l=l.split(\" \"+r.range+\" \"),i.startDate=i.startDate||i.systemDate(),i.endDate=i.endDate||i.systemDate(),r.dateTime=w.extend({},i.startDate),w.each([i.startDate,i.endDate],function(e,t){m(t,l[e],e)})):m(o,l):(i.hint(\"日期格式不合法<br>必须遵循下述格式：<br>\"+(r.range?r.format+\" \"+r.range+\" \"+r.format:r.format)+\"<br>已为你重置\"),a=!0):l&&l.constructor===Date?r.dateTime=i.systemDate(l):(r.dateTime=i.systemDate(),delete i.startState,delete i.endState,delete i.startDate,delete i.endDate,delete i.startTime,delete i.endTime),c(o),a&&l&&i.setValue(r.range?i.endDate?i.parse():\"\":i.parse()),e&&e(),i)},T.prototype.mark=function(e,t){var n,a=this,i=a.config;return w.each(i.mark,function(e,a){var i=e.split(\"-\");i[0]!=t[0]&&0!=i[0]||i[1]!=t[1]&&0!=i[1]||i[2]!=t[2]||(n=a||t[2])}),n&&e.html('<span class=\"laydate-day-mark\">'+n+\"</span>\"),a},T.prototype.limit=function(e,t,n,a){var i,r=this,o=r.config,l={},d=o[n>41?\"endDate\":\"dateTime\"],c=w.extend({},d,t||{});return w.each({now:c,min:o.min,max:o.max},function(e,t){l[e]=r.newDate(w.extend({year:t.year,month:t.month,date:t.date},function(){var e={};return w.each(a,function(n,a){e[a]=t[a]}),e}())).getTime()}),i=l.now<l.min||l.now>l.max,e&&e[i?\"addClass\":\"removeClass\"](s),i},T.prototype.calendar=function(e){var t,a,i,r=this,s=r.config,l=e||s.dateTime,c=new Date,m=r.lang(),u=\"date\"!==s.type&&\"datetime\"!==s.type,h=e?1:0,y=w(r.table[h]).find(\"td\"),f=w(r.elemHeader[h][2]).find(\"span\");if(l.year<d[0]&&(l.year=d[0],r.hint(\"最低只能支持到公元\"+d[0]+\"年\")),l.year>d[1]&&(l.year=d[1],r.hint(\"最高只能支持到公元\"+d[1]+\"年\")),r.firstDate||(r.firstDate=w.extend({},l)),c.setFullYear(l.year,l.month,1),t=c.getDay(),a=n.getEndDate(l.month||12,l.year),i=n.getEndDate(l.month+1,l.year),w.each(y,function(e,n){var d=[l.year,l.month],c=0;n=w(n),n.removeAttr(\"class\"),e<t?(c=a-t+e,n.addClass(\"laydate-day-prev\"),d=r.getAsYM(l.year,l.month,\"sub\")):e>=t&&e<i+t?(c=e-t,s.range||c+1===l.date&&n.addClass(o)):(c=e-i-t,n.addClass(\"laydate-day-next\"),d=r.getAsYM(l.year,l.month)),d[1]++,d[2]=c+1,n.attr(\"lay-ymd\",d.join(\"-\")).html(d[2]),r.mark(n,d).limit(n,{year:d[0],month:d[1]-1,date:d[2]},e)}),w(f[0]).attr(\"lay-ym\",l.year+\"-\"+(l.month+1)),w(f[1]).attr(\"lay-ym\",l.year+\"-\"+(l.month+1)),\"cn\"===s.lang?(w(f[0]).attr(\"lay-type\",\"year\").html(l.year+\"年\"),w(f[1]).attr(\"lay-type\",\"month\").html(l.month+1+\"月\")):(w(f[0]).attr(\"lay-type\",\"month\").html(m.month[l.month]),w(f[1]).attr(\"lay-type\",\"year\").html(l.year)),u&&(s.range&&(e?r.endDate=r.endDate||{year:l.year+(\"year\"===s.type?1:0),month:l.month+(\"month\"===s.type?0:-1)}:r.startDate=r.startDate||{year:l.year,month:l.month},e&&(r.listYM=[[r.startDate.year,r.startDate.month+1],[r.endDate.year,r.endDate.month+1]],r.list(s.type,0).list(s.type,1),\"time\"===s.type?r.setBtnStatus(\"时间\",w.extend({},r.systemDate(),r.startTime),w.extend({},r.systemDate(),r.endTime)):r.setBtnStatus(!0))),s.range||(r.listYM=[[l.year,l.month+1]],r.list(s.type,0))),s.range&&!e){var p=r.getAsYM(l.year,l.month);r.calendar(w.extend({},l,{year:p[0],month:p[1]}))}return s.range||r.limit(w(r.footer).find(g),null,0,[\"hours\",\"minutes\",\"seconds\"]),s.range&&e&&!u&&r.stampRange(),r},T.prototype.list=function(e,t){var n=this,a=n.config,i=a.dateTime,r=n.lang(),l=a.range&&\"date\"!==a.type&&\"datetime\"!==a.type,d=w.elem(\"ul\",{\"class\":m+\" \"+{year:\"laydate-year-list\",month:\"laydate-month-list\",time:\"laydate-time-list\"}[e]}),c=n.elemHeader[t],u=w(c[2]).find(\"span\"),h=n.elemCont[t||0],y=w(h).find(\".\"+m)[0],f=\"cn\"===a.lang,p=f?\"年\":\"\",T=n.listYM[t]||{},C=[\"hours\",\"minutes\",\"seconds\"],x=[\"startTime\",\"endTime\"][t];if(T[0]<1&&(T[0]=1),\"year\"===e){var M,b=M=T[0]-7;b<1&&(b=M=1),w.each(new Array(15),function(e){var i=w.elem(\"li\",{\"lay-ym\":M}),r={year:M};M==T[0]&&w(i).addClass(o),i.innerHTML=M+p,d.appendChild(i),M<n.firstDate.year?(r.month=a.min.month,r.date=a.min.date):M>=n.firstDate.year&&(r.month=a.max.month,r.date=a.max.date),n.limit(w(i),r,t),M++}),w(u[f?0:1]).attr(\"lay-ym\",M-8+\"-\"+T[1]).html(b+p+\" - \"+(M-1+p))}else if(\"month\"===e)w.each(new Array(12),function(e){var i=w.elem(\"li\",{\"lay-ym\":e}),s={year:T[0],month:e};e+1==T[1]&&w(i).addClass(o),i.innerHTML=r.month[e]+(f?\"月\":\"\"),d.appendChild(i),T[0]<n.firstDate.year?s.date=a.min.date:T[0]>=n.firstDate.year&&(s.date=a.max.date),n.limit(w(i),s,t)}),w(u[f?0:1]).attr(\"lay-ym\",T[0]+\"-\"+T[1]).html(T[0]+p);else if(\"time\"===e){var E=function(){w(d).find(\"ol\").each(function(e,a){w(a).find(\"li\").each(function(a,i){n.limit(w(i),[{hours:a},{hours:n[x].hours,minutes:a},{hours:n[x].hours,minutes:n[x].minutes,seconds:a}][e],t,[[\"hours\"],[\"hours\",\"minutes\"],[\"hours\",\"minutes\",\"seconds\"]][e])})}),a.range||n.limit(w(n.footer).find(g),n[x],0,[\"hours\",\"minutes\",\"seconds\"])};a.range?n[x]||(n[x]={hours:0,minutes:0,seconds:0}):n[x]=i,w.each([24,60,60],function(e,t){var a=w.elem(\"li\"),i=[\"<p>\"+r.time[e]+\"</p><ol>\"];w.each(new Array(t),function(t){i.push(\"<li\"+(n[x][C[e]]===t?' class=\"'+o+'\"':\"\")+\">\"+w.digit(t,2)+\"</li>\")}),a.innerHTML=i.join(\"\")+\"</ol>\",d.appendChild(a)}),E()}if(y&&h.removeChild(y),h.appendChild(d),\"year\"===e||\"month\"===e)w(n.elemMain[t]).addClass(\"laydate-ym-show\"),w(d).find(\"li\").on(\"click\",function(){var r=0|w(this).attr(\"lay-ym\");if(!w(this).hasClass(s)){if(0===t)i[e]=r,l&&(n.startDate[e]=r),n.limit(w(n.footer).find(g),null,0);else if(l)n.endDate[e]=r;else{var c=\"year\"===e?n.getAsYM(r,T[1]-1,\"sub\"):n.getAsYM(T[0],r,\"sub\");w.extend(i,{year:c[0],month:c[1]})}\"year\"===a.type||\"month\"===a.type?(w(d).find(\".\"+o).removeClass(o),w(this).addClass(o),\"month\"===a.type&&\"year\"===e&&(n.listYM[t][0]=r,l&&(n[[\"startDate\",\"endDate\"][t]].year=r),n.list(\"month\",t))):(n.checkDate(\"limit\").calendar(),n.closeList()),n.setBtnStatus(),a.range||n.done(null,\"change\"),w(n.footer).find(D).removeClass(s)}});else{var S=w.elem(\"span\",{\"class\":v}),k=function(){w(d).find(\"ol\").each(function(e){var t=this,a=w(t).find(\"li\");t.scrollTop=30*(n[x][C[e]]-2),t.scrollTop<=0&&a.each(function(e,n){if(!w(this).hasClass(s))return t.scrollTop=30*(e-2),!0})})},H=w(c[2]).find(\".\"+v);k(),S.innerHTML=a.range?[r.startTime,r.endTime][t]:r.timeTips,w(n.elemMain[t]).addClass(\"laydate-time-show\"),H[0]&&H.remove(),c[2].appendChild(S),w(d).find(\"ol\").each(function(e){var t=this;w(t).find(\"li\").on(\"click\",function(){var r=0|this.innerHTML;w(this).hasClass(s)||(a.range?n[x][C[e]]=r:i[C[e]]=r,w(t).find(\".\"+o).removeClass(o),w(this).addClass(o),E(),k(),(n.endDate||\"time\"===a.type)&&n.done(null,\"change\"),n.setBtnStatus())})})}return n},T.prototype.listYM=[],T.prototype.closeList=function(){var e=this;e.config;w.each(e.elemCont,function(t,n){w(this).find(\".\"+m).remove(),w(e.elemMain[t]).removeClass(\"laydate-ym-show laydate-time-show\")}),w(e.elem).find(\".\"+v).remove()},T.prototype.setBtnStatus=function(e,t,n){var a,i=this,r=i.config,o=w(i.footer).find(g),d=r.range&&\"date\"!==r.type&&\"time\"!==r.type;d&&(t=t||i.startDate,n=n||i.endDate,a=i.newDate(t).getTime()>i.newDate(n).getTime(),i.limit(null,t)||i.limit(null,n)?o.addClass(s):o[a?\"addClass\":\"removeClass\"](s),e&&a&&i.hint(\"string\"==typeof e?l.replace(/日期/g,e):l))},T.prototype.parse=function(e,t){var n=this,a=n.config,i=t||(e?w.extend({},n.endDate,n.endTime):a.range?w.extend({},n.startDate,n.startTime):a.dateTime),r=n.format.concat();return w.each(r,function(e,t){/yyyy|y/.test(t)?r[e]=w.digit(i.year,t.length):/MM|M/.test(t)?r[e]=w.digit(i.month+1,t.length):/dd|d/.test(t)?r[e]=w.digit(i.date,t.length):/HH|H/.test(t)?r[e]=w.digit(i.hours,t.length):/mm|m/.test(t)?r[e]=w.digit(i.minutes,t.length):/ss|s/.test(t)&&(r[e]=w.digit(i.seconds,t.length))}),a.range&&!e?r.join(\"\")+\" \"+a.range+\" \"+n.parse(1):r.join(\"\")},T.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},T.prototype.setValue=function(e){var t=this,n=t.config,a=t.bindElem||n.elem[0],i=t.isInput(a)?\"val\":\"html\";return\"static\"===n.position||w(a)[i](e||\"\"),this},T.prototype.stampRange=function(){var e,t,n=this,a=n.config,i=w(n.elem).find(\"td\");if(a.range&&!n.endDate&&w(n.footer).find(g).addClass(s),n.endDate)return e=n.newDate({year:n.startDate.year,month:n.startDate.month,date:n.startDate.date}).getTime(),t=n.newDate({year:n.endDate.year,month:n.endDate.month,date:n.endDate.date}).getTime(),e>t?n.hint(l):void w.each(i,function(a,i){var r=w(i).attr(\"lay-ymd\").split(\"-\"),s=n.newDate({year:r[0],month:r[1]-1,date:r[2]}).getTime();w(i).removeClass(u+\" \"+o),s!==e&&s!==t||w(i).addClass(w(i).hasClass(y)||w(i).hasClass(f)?u:o),s>e&&s<t&&w(i).addClass(u)})},T.prototype.done=function(e,t){var n=this,a=n.config,i=w.extend({},n.startDate?w.extend(n.startDate,n.startTime):a.dateTime),r=w.extend({},w.extend(n.endDate,n.endTime));return w.each([i,r],function(e,t){\"month\"in t&&w.extend(t,{month:t.month+1})}),e=e||[n.parse(),i,r],\"function\"==typeof a[t||\"done\"]&&a[t||\"done\"].apply(a,e),n},T.prototype.choose=function(e){var t=this,n=t.config,a=n.dateTime,i=w(t.elem).find(\"td\"),r=e.attr(\"lay-ymd\").split(\"-\"),l=function(e){new Date;e&&w.extend(a,r),n.range&&(t.startDate?w.extend(t.startDate,r):t.startDate=w.extend({},r,t.startTime),t.startYMD=r)};if(r={year:0|r[0],month:(0|r[1])-1,date:0|r[2]},!e.hasClass(s))if(n.range){if(w.each([\"startTime\",\"endTime\"],function(e,n){t[n]=t[n]||{hours:0,minutes:0,seconds:0}}),t.endState)l(),delete t.endState,delete t.endDate,t.startState=!0,i.removeClass(o+\" \"+u),e.addClass(o);else if(t.startState){if(e.addClass(o),t.endDate?w.extend(t.endDate,r):t.endDate=w.extend({},r,t.endTime),t.newDate(r).getTime()<t.newDate(t.startYMD).getTime()){var d=w.extend({},t.endDate,{hours:t.startDate.hours,minutes:t.startDate.minutes,seconds:t.startDate.seconds});w.extend(t.endDate,t.startDate,{hours:t.endDate.hours,minutes:t.endDate.minutes,seconds:t.endDate.seconds}),t.startDate=d}n.showBottom||t.done(),t.stampRange(),t.endState=!0,t.done(null,\"change\")}else e.addClass(o),l(),t.startState=!0;w(t.footer).find(g)[t.endDate?\"removeClass\":\"addClass\"](s)}else\"static\"===n.position?(l(!0),t.calendar().done().done(null,\"change\")):\"date\"===n.type?(l(!0),t.setValue(t.parse()).remove().done()):\"datetime\"===n.type&&(l(!0),t.calendar().done(null,\"change\"))},T.prototype.tool=function(e,t){var n=this,a=n.config,i=a.dateTime,r=\"static\"===a.position,o={datetime:function(){w(e).hasClass(s)||(n.list(\"time\",0),a.range&&n.list(\"time\",1),w(e).attr(\"lay-type\",\"date\").html(n.lang().dateTips))},date:function(){n.closeList(),w(e).attr(\"lay-type\",\"datetime\").html(n.lang().timeTips)},clear:function(){n.setValue(\"\").remove(),r&&(w.extend(i,n.firstDate),n.calendar()),a.range&&(delete n.startState,delete n.endState,delete n.endDate,delete n.startTime,delete n.endTime),n.done([\"\",{},{}])},now:function(){var e=new Date;w.extend(i,n.systemDate(),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()}),n.setValue(n.parse()).remove(),r&&n.calendar(),n.done()},confirm:function(){if(a.range){if(!n.endDate)return n.hint(\"请先选择日期范围\");if(w(e).hasClass(s))return n.hint(\"time\"===a.type?l.replace(/日期/g,\"时间\"):l)}else if(w(e).hasClass(s))return n.hint(\"不在有效日期或时间范围内\");n.done(),n.setValue(n.parse()).remove()}};o[t]&&o[t]()},T.prototype.change=function(e){var t=this,n=t.config,a=n.dateTime,i=n.range&&(\"year\"===n.type||\"month\"===n.type),r=t.elemCont[e||0],o=t.listYM[e],s=function(s){var l=[\"startDate\",\"endDate\"][e],d=w(r).find(\".laydate-year-list\")[0],c=w(r).find(\".laydate-month-list\")[0];return d&&(o[0]=s?o[0]-15:o[0]+15,t.list(\"year\",e)),c&&(s?o[0]--:o[0]++,t.list(\"month\",e)),(d||c)&&(w.extend(a,{year:o[0]}),i&&(t[l].year=o[0]),n.range||t.done(null,\"change\"),t.setBtnStatus(),n.range||t.limit(w(t.footer).find(g),{year:o[0]})),d||c};return{prevYear:function(){s(\"sub\")||(a.year--,t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\"))},prevMonth:function(){var e=t.getAsYM(a.year,a.month,\"sub\");w.extend(a,{year:e[0],month:e[1]}),t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\")},nextMonth:function(){var e=t.getAsYM(a.year,a.month);w.extend(a,{year:e[0],month:e[1]}),t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\")},nextYear:function(){s()||(a.year++,t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\"))}}},T.prototype.changeEvent=function(){var e=this;e.config;w(e.elem).on(\"click\",function(e){w.stope(e)}),w.each(e.elemHeader,function(t,n){w(n[0]).on(\"click\",function(n){e.change(t).prevYear()}),w(n[1]).on(\"click\",function(n){e.change(t).prevMonth()}),w(n[2]).find(\"span\").on(\"click\",function(n){var a=w(this),i=a.attr(\"lay-ym\"),r=a.attr(\"lay-type\");i&&(i=i.split(\"-\"),e.listYM[t]=[0|i[0],0|i[1]],e.list(r,t),w(e.footer).find(D).addClass(s))}),w(n[3]).on(\"click\",function(n){e.change(t).nextMonth()}),w(n[4]).on(\"click\",function(n){e.change(t).nextYear()})}),w.each(e.table,function(t,n){var a=w(n).find(\"td\");a.on(\"click\",function(){e.choose(w(this))})}),w(e.footer).find(\"span\").on(\"click\",function(){var t=w(this).attr(\"lay-type\");e.tool(this,t)})},T.prototype.isInput=function(e){return/input|textarea/.test(e.tagName.toLocaleLowerCase())},T.prototype.events=function(){var e=this,t=e.config,n=function(n,a){n.on(t.trigger,function(){a&&(e.bindElem=this),e.render()})};t.elem[0]&&!t.elem[0].eventHandler&&(n(t.elem,\"bind\"),n(t.eventElem),w(document).on(\"click\",function(n){n.target!==t.elem[0]&&n.target!==t.eventElem[0]&&n.target!==w(t.closeStop)[0]&&e.remove()}).on(\"keydown\",function(t){13===t.keyCode&&w(\"#\"+e.elemID)[0]&&e.elemID===T.thisElem&&(t.preventDefault(),w(e.footer).find(g)[0].click())}),w(window).on(\"resize\",function(){return!(!e.elem||!w(r)[0])&&void e.position()}),t.elem[0].eventHandler=!0)},n.render=function(e){var t=new T(e);return a.call(t)},n.getEndDate=function(e,t){var n=new Date;return n.setFullYear(t||n.getFullYear(),e||n.getMonth()+1,1),new Date(n.getTime()-864e5).getDate()},window.lay=window.lay||w,e?(n.ready(),layui.define(function(e){n.path=layui.cache.dir,e(i,n)})):\"function\"==typeof define&&define.amd?define(function(){return n}):function(){n.ready(),window.laydate=n}()}();"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/layedit.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define([\"layer\",\"form\"],function(t){\"use strict\";var e=layui.$,i=layui.layer,a=layui.form,l=(layui.hint(),layui.device()),n=\"layedit\",o=\"layui-show\",r=\"layui-disabled\",c=function(){var t=this;t.index=0,t.config={tool:[\"strong\",\"italic\",\"underline\",\"del\",\"|\",\"left\",\"center\",\"right\",\"|\",\"link\",\"unlink\",\"face\",\"image\"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r=\"layui-layedit\",c=e(\"string\"==typeof t?\"#\"+t:t),u=\"LAY_layedit_\"+ ++a.index,d=c.next(\".\"+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join(\"\")}(),m=e(['<div class=\"'+r+'\">','<div class=\"layui-unselect layui-layedit-tool\">'+f+\"</div>\",'<div class=\"layui-layedit-iframe\">','<iframe id=\"'+u+'\" name=\"'+u+'\" textarea=\"'+t+'\" frameborder=\"0\"></iframe>',\"</div>\",\"</div>\"].join(\"\"));return l.ie&&l.ie<8?c.removeClass(\"layui-hide\").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass(\"layui-hide\").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e(\"#\"+i[1].attr(\"textarea\"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find(\"iframe\");n.css({height:a.height}).on(\"load\",function(){var o=n.contents(),r=n.prop(\"contentWindow\"),c=o.find(\"head\"),s=e([\"<style>\",\"*{margin: 0; padding: 0;}\",\"body{padding: 10px; line-height: 20px; overflow-x: hidden; word-wrap: break-word; font: 14px Helvetica Neue,Helvetica,PingFang SC,Microsoft YaHei,Tahoma,Arial,sans-serif; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;}\",\"a{color:#01AAED; text-decoration:none;}a:hover{color:#c00}\",\"p{margin-bottom: 10px;}\",\"img{display: inline-block; border: none; vertical-align: middle;}\",\"pre{margin: 10px 0; padding: 10px; line-height: 20px; border: 1px solid #ddd; border-left-width: 6px; background-color: #F2F2F2; color: #333; font-family: Courier New; font-size: 12px;}\",\"</style>\"].join(\"\")),u=o.find(\"body\");c.append(s),u.attr(\"contenteditable\",\"true\").css({\"min-height\":a.height}).html(i.value||\"\"),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e(\"#LAY_layedit_\"+t),a=i.prop(\"contentWindow\");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on(\"keydown\",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if(\"pre\"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg(\"请暂时用shift+enter\"),!1}r.execCommand(\"formatBlock\",!1,\"<p>\")}}),e(n).parents(\"form\").on(\"submit\",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on(\"paste\",function(e){r.execCommand(\"formatBlock\",!1,\"<p>\"),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find(\"*[style]\").each(function(){var t=this.style.textAlign;this.removeAttribute(\"style\"),e(this).css({\"text-align\":t||\"\"})}),t.find(\"table\").addClass(\"layui-table\"),t.find(\"script,link\").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute(\"text\"),l.selection){var r=a.text||i.text;if(\"a\"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop(\"outerHTML\")),a.select()}else{var r=a.toString()||i.text;if(\"a\"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l=\"layedit-tool-active\",n=p(m(a)),o=function(e){return t.find(\".layedit-tool-\"+e)};i&&i[i.hasClass(l)?\"removeClass\":\"addClass\"](l),t.find(\">i\").removeClass(l),o(\"unlink\").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;\"b\"!==t&&\"strong\"!==t||o(\"b\").addClass(l),\"i\"!==t&&\"em\"!==t||o(\"i\").addClass(l),\"u\"===t&&o(\"u\").addClass(l),\"strike\"===t&&o(\"d\").addClass(l),\"p\"===t&&(\"center\"===e?o(\"center\").addClass(l):\"right\"===e?o(\"right\").addClass(l):o(\"left\").addClass(l)),\"a\"===t&&(o(\"link\").addClass(l),o(\"unlink\").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr(\"href\"),target:l.attr(\"target\")},function(e){var a=l[0];\"A\"===a.tagName?a.href=e.url:v.call(t,\"a\",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand(\"unlink\")},face:function(e){x.call(this,function(i){v.call(t,\"img\",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use(\"upload\",function(o){var r=l.uploadImage||{};o.render({url:r.url,method:r.type,elem:e(n).find(\"input\")[0],done:function(e){0==e.code?(e.data=e.data||{},v.call(t,\"img\",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||\"上传失败\")}})})},code:function(e){k.call(o,function(i){v.call(t,\"pre\",{text:i.code,\"lay-lang\":i.lang},e)})},help:function(){i.open({type:2,title:\"帮助\",area:[\"600px\",\"380px\"],shadeClose:!0,shade:.1,skin:\"layui-layer-msg\",content:[\"http://www.layui.com/about/layedit/help.html\",\"no\"]})}},s=a.find(\".layui-layedit-tool\"),u=function(){var i=e(this),a=i.attr(\"layedit-event\"),l=i.attr(\"lay-command\");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand(\"formatBlock\",!1,\"<p>\"),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(\">i\").on(\"mousedown\",function(){var t=e(this),i=t.attr(\"layedit-event\");d.test(i)||u.call(this)}).on(\"click\",function(){var t=e(this),i=t.attr(\"layedit-event\");d.test(i)&&u.call(this)}),o.on(\"click\",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:\"LAY_layedit_link\",area:\"350px\",shade:.05,shadeClose:!0,moveType:1,title:\"超链接\",skin:\"layui-layer-msg\",content:['<ul class=\"layui-form\" style=\"margin: 15px;\">','<li class=\"layui-form-item\">','<label class=\"layui-form-label\" style=\"width: 60px;\">URL</label>','<div class=\"layui-input-block\" style=\"margin-left: 90px\">','<input name=\"url\" lay-verify=\"url\" value=\"'+(t.href||\"\")+'\" autofocus=\"true\" autocomplete=\"off\" class=\"layui-input\">',\"</div>\",\"</li>\",'<li class=\"layui-form-item\">','<label class=\"layui-form-label\" style=\"width: 60px;\">打开方式</label>','<div class=\"layui-input-block\" style=\"margin-left: 90px\">','<input type=\"radio\" name=\"target\" value=\"_self\" class=\"layui-input\" title=\"当前窗口\"'+(\"_self\"!==t.target&&t.target?\"\":\"checked\")+\">\",'<input type=\"radio\" name=\"target\" value=\"_blank\" class=\"layui-input\" title=\"新窗口\" '+(\"_blank\"===t.target?\"checked\":\"\")+\">\",\"</div>\",\"</li>\",'<li class=\"layui-form-item\" style=\"text-align: center;\">','<button type=\"button\" lay-submit lay-filter=\"layedit-link-yes\" class=\"layui-btn\"> 确定 </button>','<button style=\"margin-left: 20px;\" type=\"button\" class=\"layui-btn layui-btn-primary\"> 取消 </button>',\"</li>\",\"</ul>\"].join(\"\"),success:function(t,n){var o=\"submit(layedit-link-yes)\";a.render(\"radio\"),t.find(\".layui-btn-primary\").on(\"click\",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=[\"[微笑]\",\"[嘻嘻]\",\"[哈哈]\",\"[可爱]\",\"[可怜]\",\"[挖鼻]\",\"[吃惊]\",\"[害羞]\",\"[挤眼]\",\"[闭嘴]\",\"[鄙视]\",\"[爱你]\",\"[泪]\",\"[偷笑]\",\"[亲亲]\",\"[生病]\",\"[太开心]\",\"[白眼]\",\"[右哼哼]\",\"[左哼哼]\",\"[嘘]\",\"[衰]\",\"[委屈]\",\"[吐]\",\"[哈欠]\",\"[抱抱]\",\"[怒]\",\"[疑问]\",\"[馋嘴]\",\"[拜拜]\",\"[思考]\",\"[汗]\",\"[困]\",\"[睡]\",\"[钱]\",\"[失望]\",\"[酷]\",\"[色]\",\"[哼]\",\"[鼓掌]\",\"[晕]\",\"[悲伤]\",\"[抓狂]\",\"[黑线]\",\"[阴险]\",\"[怒骂]\",\"[互粉]\",\"[心]\",\"[伤心]\",\"[猪头]\",\"[熊猫]\",\"[兔子]\",\"[ok]\",\"[耶]\",\"[good]\",\"[NO]\",\"[赞]\",\"[来]\",\"[弱]\",\"[草泥马]\",\"[神马]\",\"[囧]\",\"[浮云]\",\"[给力]\",\"[围观]\",\"[威武]\",\"[奥特曼]\",\"[礼物]\",\"[钟]\",\"[话筒]\",\"[蜡烛]\",\"[蛋糕]\"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+\"images/face/\"+t+\".gif\"}),e}();return x.hide=x.hide||function(t){\"face\"!==e(t.target).attr(\"layedit-event\")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('<li title=\"'+e+'\"><img src=\"'+i+'\" alt=\"'+e+'\"></li>')}),'<ul class=\"layui-clear\">'+t.join(\"\")+\"</ul>\"}(),this,{tips:1,time:0,skin:\"layui-box layui-util-face\",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(\".layui-clear>li\").on(\"click\",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off(\"click\",x.hide).on(\"click\",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:\"LAY_layedit_code\",area:\"550px\",shade:.05,shadeClose:!0,moveType:1,title:\"插入代码\",skin:\"layui-layer-msg\",content:['<ul class=\"layui-form layui-form-pane\" style=\"margin: 15px;\">','<li class=\"layui-form-item\">','<label class=\"layui-form-label\">请选择语言</label>','<div class=\"layui-input-block\">','<select name=\"lang\">','<option value=\"JavaScript\">JavaScript</option>','<option value=\"HTML\">HTML</option>','<option value=\"CSS\">CSS</option>','<option value=\"Java\">Java</option>','<option value=\"PHP\">PHP</option>','<option value=\"C#\">C#</option>','<option value=\"Python\">Python</option>','<option value=\"Ruby\">Ruby</option>','<option value=\"Go\">Go</option>',\"</select>\",\"</div>\",\"</li>\",'<li class=\"layui-form-item layui-form-text\">','<label class=\"layui-form-label\">代码</label>','<div class=\"layui-input-block\">','<textarea name=\"code\" lay-verify=\"required\" autofocus=\"true\" class=\"layui-textarea\" style=\"height: 200px;\"></textarea>',\"</div>\",\"</li>\",'<li class=\"layui-form-item\" style=\"text-align: center;\">','<button type=\"button\" lay-submit lay-filter=\"layedit-code-yes\" class=\"layui-btn\"> 确定 </button>','<button style=\"margin-left: 20px;\" type=\"button\" class=\"layui-btn layui-btn-primary\"> 取消 </button>',\"</li>\",\"</ul>\"].join(\"\"),success:function(l,n){var o=\"submit(layedit-code-yes)\";a.render(\"select\"),l.find(\".layui-btn-primary\").on(\"click\",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'<i class=\"layui-icon layedit-tool-html\" title=\"HTML源代码\" lay-command=\"html\" layedit-event=\"html\"\">&#xe64b;</i><span class=\"layedit-tool-mid\"></span>',strong:'<i class=\"layui-icon layedit-tool-b\" title=\"加粗\" lay-command=\"Bold\" layedit-event=\"b\"\">&#xe62b;</i>',italic:'<i class=\"layui-icon layedit-tool-i\" title=\"斜体\" lay-command=\"italic\" layedit-event=\"i\"\">&#xe644;</i>',underline:'<i class=\"layui-icon layedit-tool-u\" title=\"下划线\" lay-command=\"underline\" layedit-event=\"u\"\">&#xe646;</i>',del:'<i class=\"layui-icon layedit-tool-d\" title=\"删除线\" lay-command=\"strikeThrough\" layedit-event=\"d\"\">&#xe64f;</i>',\"|\":'<span class=\"layedit-tool-mid\"></span>',left:'<i class=\"layui-icon layedit-tool-left\" title=\"左对齐\" lay-command=\"justifyLeft\" layedit-event=\"left\"\">&#xe649;</i>',center:'<i class=\"layui-icon layedit-tool-center\" title=\"居中对齐\" lay-command=\"justifyCenter\" layedit-event=\"center\"\">&#xe647;</i>',right:'<i class=\"layui-icon layedit-tool-right\" title=\"右对齐\" lay-command=\"justifyRight\" layedit-event=\"right\"\">&#xe648;</i>',link:'<i class=\"layui-icon layedit-tool-link\" title=\"插入链接\" layedit-event=\"link\"\">&#xe64c;</i>',unlink:'<i class=\"layui-icon layedit-tool-unlink layui-disabled\" title=\"清除链接\" lay-command=\"unlink\" layedit-event=\"unlink\"\">&#xe64d;</i>',face:'<i class=\"layui-icon layedit-tool-face\" title=\"表情\" layedit-event=\"face\"\">&#xe650;</i>',image:'<i class=\"layui-icon layedit-tool-image\" title=\"图片\" layedit-event=\"image\">&#xe64a;<input type=\"file\" name=\"file\"></i>',code:'<i class=\"layui-icon layedit-tool-code\" title=\"插入代码\" layedit-event=\"code\">&#xe64e;</i>',help:'<i class=\"layui-icon layedit-tool-help\" title=\"帮助\" layedit-event=\"help\">&#xe607;</i>'},w=new c;t(n,w)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/layer.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;!function(e,t){\"use strict\";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if(\"interactive\"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],type:[\"dialog\",\"page\",\"iframe\",\"loading\",\"tips\"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName(\"head\")[0],s=document.createElement(\"link\");\"string\"==typeof i&&(n=i);var l=(n||t).replace(/\\.|\\//g,\"\"),f=\"layuicss-\"+l,c=0;s.rel=\"stylesheet\",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),\"function\"==typeof i&&!function u(){return++c>80?e.console&&console.error(\"layer.css: Invalid\"):void(1989===parseInt(o.getStyle(document.getElementById(f),\"width\"))?i():setTimeout(u,100))}()}}},r={v:\"3.1.1\",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||\"ActiveXObject\"in e)&&((t.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,\"string\"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss(\"modules/layer/\"+e.extend):o.link(\"theme/\"+e.extend),this):this},ready:function(e){var t=\"layer\",i=\"\",n=(a?\"modules/layer/\":\"theme/\")+\"default/layer.css?v=\"+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a=\"function\"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s=\"function\"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s=\"function\"==typeof n,f=o.config.skin,c=(f?f+\" \"+f+\"-msg\":\"\")||\"layui-layer-msg\",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+\" layui-layer-hui\",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+\" \"+(n.skin||\"layui-layer-hui\")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=[\"layui-layer\",\".layui-layer-title\",\".layui-layer-main\",\".layui-layer-dialog\",\"layui-layer-iframe\",\"layui-layer-content\",\"layui-layer-btn\",\"layui-layer-close\"];l.anim=[\"layer-anim-00\",\"layer-anim-01\",\"layer-anim-02\",\"layer-anim-03\",\"layer-anim-04\",\"layer-anim-05\",\"layer-anim-06\"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:\"&#x4FE1;&#x606F;\",offset:\"auto\",area:\"auto\",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f=\"object\"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'<div class=\"layui-layer-title\" style=\"'+(f?r.title[1]:\"\")+'\">'+(f?r.title[0]:r.title)+\"</div>\":\"\";return r.zIndex=s,t([r.shade?'<div class=\"layui-layer-shade\" id=\"layui-layer-shade'+a+'\" times=\"'+a+'\" style=\"'+(\"z-index:\"+(s-1)+\"; \")+'\"></div>':\"\",'<div class=\"'+l[0]+(\" layui-layer-\"+o.type[r.type])+(0!=r.type&&2!=r.type||r.shade?\"\":\" layui-layer-border\")+\" \"+(r.skin||\"\")+'\" id=\"'+l[0]+a+'\" type=\"'+o.type[r.type]+'\" times=\"'+a+'\" showtime=\"'+r.time+'\" conType=\"'+(e?\"object\":\"string\")+'\" style=\"z-index: '+s+\"; width:\"+r.area[0]+\";height:\"+r.area[1]+(r.fixed?\"\":\";position:absolute;\")+'\">'+(e&&2!=r.type?\"\":u)+'<div id=\"'+(r.id||\"\")+'\" class=\"layui-layer-content'+(0==r.type&&r.icon!==-1?\" layui-layer-padding\":\"\")+(3==r.type?\" layui-layer-loading\"+r.icon:\"\")+'\">'+(0==r.type&&r.icon!==-1?'<i class=\"layui-layer-ico layui-layer-ico'+r.icon+'\"></i>':\"\")+(1==r.type&&e?\"\":r.content||\"\")+'</div><span class=\"layui-layer-setwin\">'+function(){var e=c?'<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>':\"\";return r.closeBtn&&(e+='<a class=\"layui-layer-ico '+l[7]+\" \"+l[7]+(r.title?r.closeBtn:4==r.type?\"1\":\"2\")+'\" href=\"javascript:;\"></a>'),e}()+\"</span>\"+(r.btn?function(){var e=\"\";\"string\"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t<i;t++)e+='<a class=\"'+l[6]+t+'\">'+r.btn[t]+\"</a>\";return'<div class=\"'+l[6]+\" layui-layer-btn-\"+(r.btnAlign||\"\")+'\">'+e+\"</div>\"}():\"\")+(r.resize?'<span class=\"layui-layer-resize\"></span>':\"\")+\"</div>\"],u,i('<div class=\"layui-layer-move\"></div>')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f=\"object\"==typeof s,c=i(\"body\");if(!t.id||!i(\"#\"+t.id)[0]){switch(\"string\"==typeof t.area&&(t.area=\"auto\"===t.area?[\"\",\"\"]:[t.area,\"\"]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn=\"btn\"in t?t.btn:o.btn[0],r.closeAll(\"dialog\");break;case 2:var s=t.content=f?t.content:[t.content||\"\",\"auto\"];t.content='<iframe scrolling=\"'+(t.content[1]||\"auto\")+'\" allowtransparency=\"true\" id=\"'+l[4]+a+'\" name=\"'+l[4]+a+'\" onload=\"this.className=\\'\\';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"'+t.content[0]+'\"></iframe>';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll(\"loading\");break;case 4:f||(t.content=[t.content,\"body\"]),t.follow=t.content[1],t.content=t.content[0]+'<i class=\"layui-layer-TipsG\"></i>',delete t.title,t.tips=\"object\"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll(\"tips\")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i(\"body\").append(n[1])}():function(){s.parents(\".\"+l[0])[0]||(s.data(\"display\",s.css(\"display\")).show().addClass(\"layui-layer-wrap\").wrap(n[1]),i(\"#\"+l[0]+a).find(\".\"+l[5]).before(r))}()}():c.append(n[1]),i(\".layui-layer-move\")[0]||c.append(o.moveElem=u),e.layero=i(\"#\"+l[0]+a),t.scrollbar||l.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",a)}).auto(a),i(\"#layui-layer-shade\"+e.index).css({\"background-color\":t.shade[1]||\"#000\",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find(\"iframe\").attr(\"src\",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on(\"resize\",function(){e.offset(),(/^\\d+%$/.test(t.area[0])||/^\\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u=\"layer-anim \"+l.anim[t.anim];e.layero.addClass(u).one(\"webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend\",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data(\"isOutAnim\",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i(\"#\"+l[0]+e);\"\"===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find(\".\"+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css(\"padding-top\"))))};switch(a.type){case 2:u(\"iframe\");break;default:\"\"===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u(\".\"+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u(\".\"+l[5])):u(\".\"+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o=\"object\"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):\"auto\"!==t.offset&&(\"t\"===t.offset?e.offsetTop=0:\"r\"===t.offset?e.offsetLeft=n.width()-a[0]:\"b\"===t.offset?e.offsetTop=n.height()-a[1]:\"l\"===t.offset?e.offsetLeft=0:\"lt\"===t.offset?(e.offsetTop=0,e.offsetLeft=0):\"lb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):\"rt\"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):\"rb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr(\"minLeft\")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css(\"left\")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i(\"body\"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(\".layui-layer-TipsG\"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:\"auto\"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass(\"layui-layer-TipsB\").addClass(\"layui-layer-TipsT\").css(\"border-right-color\",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass(\"layui-layer-TipsL\").addClass(\"layui-layer-TipsR\").css(\"border-bottom-color\",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass(\"layui-layer-TipsT\").addClass(\"layui-layer-TipsB\").css(\"border-right-color\",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass(\"layui-layer-TipsR\").addClass(\"layui-layer-TipsL\").css(\"border-bottom-color\",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find(\".\"+l[5]).css({\"background-color\":t.tips[1],\"padding-right\":t.closeBtn?\"30px\":\"\"}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(\".layui-layer-resize\"),c={};return t.move&&l.css(\"cursor\",\"move\"),l.on(\"mousedown\",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css(\"left\")),e.clientY-parseFloat(s.css(\"top\"))],o.moveElem.css(\"cursor\",\"move\").show())}),f.on(\"mousedown\",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css(\"cursor\",\"se-resize\").show()}),a.on(\"mousemove\",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l=\"fixed\"===s.css(\"position\");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;a<c.stX&&(a=c.stX),a>f&&(a=f),o<c.stY&&(o=c.stY),o>u&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on(\"mouseup\",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find(\"iframe\").on(\"load\",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find(\".\"+l[6]).children(\"a\").on(\"click\",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a[\"btn\"+(e+1)]&&a[\"btn\"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find(\".\"+l[7]).on(\"click\",e),a.shadeClose&&i(\"#layui-layer-shade\"+t.index).on(\"click\",function(){r.close(t.index)}),n.find(\".layui-layer-min\").on(\"click\",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(\".layui-layer-max\").on(\"click\",function(){i(this).hasClass(\"layui-layer-maxmin\")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i(\"select\"),function(e,t){var n=i(this);n.parents(\".\"+l[0])[0]||1==n.attr(\"layer\")&&i(\".\"+l[0]).length<1&&n.removeAttr(\"layer\").show(),n=null})},s.pt.IE6=function(e){i(\"select\").each(function(e,t){var n=i(this);n.parents(\".\"+l[0])[0]||\"none\"===n.css(\"display\")||n.attr({layer:\"1\"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css(\"z-index\",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on(\"mousedown\",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css(\"margin-left\"))];e.find(\".layui-layer-max\").addClass(\"layui-layer-maxmin\"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr(\"layer-full\")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty(\"overflow\"):l.html[0].style.removeAttribute(\"overflow\"),l.html.removeAttr(\"layer-full\"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i(\".\"+l[4]).attr(\"times\"),i(\"#\"+l[0]+t).find(\"iframe\").contents().find(e)},r.getFrameIndex=function(e){return i(\"#\"+e).parents(\".\"+l[4]).attr(\"times\")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame(\"html\",e).outerHeight(),n=i(\"#\"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find(\".\"+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find(\"iframe\").css({height:t})}},r.iframeSrc=function(e,t){i(\"#\"+l[0]+e).find(\"iframe\").attr(\"src\",t)},r.style=function(e,t,n){var a=i(\"#\"+l[0]+e),r=a.find(\".layui-layer-content\"),s=a.attr(\"type\"),f=a.find(l[1]).outerHeight()||0,c=a.find(\".\"+l[6]).outerHeight()||0;a.attr(\"minLeft\");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find(\".\"+l[6]).outerHeight(),s===o.type[2]?a.find(\"iframe\").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css(\"padding-top\"))-parseFloat(r.css(\"padding-bottom\"))}))},r.min=function(e,t){var a=i(\"#\"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr(\"minLeft\")||181*o.minIndex+\"px\",c=a.css(\"position\");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr(\"position\",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:\"fixed\",overflow:\"hidden\"},!0),a.find(\".layui-layer-min\").hide(),\"page\"===a.attr(\"type\")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr(\"minLeft\")||o.minIndex++,a.attr(\"minLeft\",f)},r.restore=function(e){var t=i(\"#\"+l[0]+e),n=t.attr(\"area\").split(\",\");t.attr(\"type\");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr(\"position\"),overflow:\"visible\"},!0),t.find(\".layui-layer-max\").removeClass(\"layui-layer-maxmin\"),t.find(\".layui-layer-min\").show(),\"page\"===t.attr(\"type\")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i(\"#\"+l[0]+e);o.record(a),l.html.attr(\"layer-full\")||l.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",e),clearTimeout(t),t=setTimeout(function(){var t=\"fixed\"===a.css(\"position\");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(\".layui-layer-min\").hide()},100)},r.title=function(e,t){var n=i(\"#\"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i(\"#\"+l[0]+e),n=t.attr(\"type\"),a=\"layer-anim-close\";if(t[0]){var s=\"layui-layer-wrap\",f=function(){if(n===o.type[1]&&\"object\"===t.attr(\"conType\")){t.children(\":not(.\"+l[5]+\")\").remove();for(var a=t.find(\".\"+s),r=0;r<2;r++)a.unwrap();a.css(\"display\",a.data(\"display\")).removeClass(s)}else{if(n===o.type[2])try{var f=i(\"#\"+l[4]+e)[0];f.contentWindow.document.write(\"\"),f.contentWindow.close(),t.find(\".\"+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML=\"\",t.remove()}\"function\"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data(\"isOutAnim\")&&t.addClass(\"layer-anim \"+a),i(\"#layui-layer-moves, #layui-layer-shade\"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr(\"minLeft\")&&(o.minIndex--,o.minLeft.push(t.attr(\"minLeft\"))),r.ie&&r.ie<10||!t.data(\"isOutAnim\")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i(\".\"+l[0]),function(){var t=i(this),n=e?t.attr(\"type\")===e:1;n&&r.close(t.attr(\"times\")),n=null})};var f=r.cache||{},c=function(e){return f.skin?\" \"+f.skin+\" \"+f.skin+\"-\"+e:\"\"};r.prompt=function(e,t){var a=\"\";if(e=e||{},\"function\"==typeof e&&(t=e),e.area){var o=e.area;a='style=\"width: '+o[0]+\"; height: \"+o[1]+';\"',delete e.area}var s,l=2==e.formType?'<textarea class=\"layui-layer-input\"'+a+\"></textarea>\":function(){return'<input type=\"'+(1==e.formType?\"password\":\"text\")+'\" class=\"layui-layer-input\">'}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:l,skin:\"layui-layer-prompt\"+c(\"prompt\"),maxWidth:n.width(),success:function(t){s=t.find(\".layui-layer-input\"),s.val(e.value||\"\").focus(),\"function\"==typeof f&&f(t)},resize:!1,yes:function(i){var n=s.val();\"\"===n?s.focus():n.length>(e.maxlength||500)?r.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(e.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n=\"layui-this\",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:\"layui-layer-tab\"+c(\"tab\"),resize:!1,title:function(){var e=t.length,i=1,a=\"\";if(e>0)for(a='<span class=\"'+n+'\">'+t[0].title+\"</span>\";i<e;i++)a+=\"<span>\"+t[i].title+\"</span>\";return a}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var e=t.length,i=1,a=\"\";if(e>0)for(a='<li class=\"layui-layer-tabli '+n+'\">'+(t[0].content||\"no content\")+\"</li>\";i<e;i++)a+='<li class=\"layui-layer-tabli\">'+(t[i].content||\"no  content\")+\"</li>\";return a}()+\"</ul>\",success:function(t){var o=t.find(\".layui-layer-title\").children(),r=t.find(\".layui-layer-tabmain\").children();o.on(\"mousedown\",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),\"function\"==typeof e.change&&e.change(o)}),\"function\"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||\"img\";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr(\"layer-index\",e),u.push({alt:t.attr(\"alt\"),pid:t.attr(\"layer-pid\"),src:t.attr(\"layer-src\")||t.attr(\"src\"),thumb:t.attr(\"src\")})})};if(h(),0===u.length)return;if(n||p.on(\"click\",t.img,function(){var e=i(this),n=e.attr(\"layer-index\");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(e){e.preventDefault(),s.imgnext()}),i(document).on(\"keyup\",s.keyup)},s.loadi=r.load(1,{shade:!(\"shade\"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:\"layui-layer-photos\",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]<r[1]&&(a[0]=a[0]/r[1],a[1]=a[1]/r[1])}return[a[0]+\"px\",a[1]+\"px\"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:\".layui-layer-phimg img\",moveType:1,scrollbar:!1,moveOut:!0,isOutAnim:!1,skin:\"layui-layer-photos\"+c(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+u[d].src+'\" alt=\"'+(u[d].alt||\"\")+'\" layer-pid=\"'+u[d].pid+'\"><div class=\"layui-layer-imgsee\">'+(u.length>1?'<span class=\"layui-layer-imguide\"><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgprev\"></a><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgnext\"></a></span>':\"\")+'<div class=\"layui-layer-imgbar\" style=\"display:'+(a?\"block\":\"\")+'\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">'+(u[d].alt||\"\")+\"</a><em>\"+s.imgIndex+\"/\"+u.length+\"</em></span></div></div></div>\",success:function(e,i){s.bigimg=e.find(\".layui-layer-phimg\"),s.imgsee=e.find(\".layui-layer-imguide,.layui-layer-imgbar\"),s.event(e),t.tab&&t.tab(u[d],e),\"function\"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off(\"keyup\",s.keyup)}},t))},function(){r.close(s.loadi),r.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"&#x4E0B;&#x4E00;&#x5F20;\",\"&#x4E0D;&#x770B;&#x4E86;\"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i(\"html\"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define(\"jquery\",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t(\"layer\",r)})):\"function\"==typeof define&&define.amd?define([\"jquery\"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/laypage.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(function(e){\"use strict\";var a=document,t=\"getElementById\",n=\"getElementsByTagName\",i=\"laypage\",r=\"layui-disabled\",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if(\"object\"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups=\"groups\"in a?0|a.groups:5;a.layout=\"object\"==typeof a.layout?a.layout:[\"prev\",\"page\",\"next\"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits=\"object\"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev=\"prev\"in a?a.prev:\"&#x4E0A;&#x4E00;&#x9875;\",a.next=\"next\"in a?a.next:\"&#x4E0B;&#x4E00;&#x9875;\";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?'<a href=\"javascript:;\" class=\"layui-laypage-prev'+(1==a.curr?\" \"+r:\"\")+'\" data-page=\"'+(a.curr-1)+'\">'+a.prev+\"</a>\":\"\"}(),page:function(){var e=[];if(a.count<1)return\"\";n>1&&a.first!==!1&&0!==t&&e.push('<a href=\"javascript:;\" class=\"layui-laypage-first\" data-page=\"1\"  title=\"&#x9996;&#x9875;\">'+(a.first||1)+\"</a>\");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r<t-1&&(r=u-t+1),a.first!==!1&&r>2&&e.push('<span class=\"layui-laypage-spr\">&#x2026;</span>');r<=u;r++)r===a.curr?e.push('<span class=\"layui-laypage-curr\"><em class=\"layui-laypage-em\" '+(/^#/.test(a.theme)?'style=\"background-color:'+a.theme+';\"':\"\")+\"></em><em>\"+r+\"</em></span>\"):e.push('<a href=\"javascript:;\" data-page=\"'+r+'\">'+r+\"</a>\");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1<a.pages&&e.push('<span class=\"layui-laypage-spr\">&#x2026;</span>'),0!==t&&e.push('<a href=\"javascript:;\" class=\"layui-laypage-last\" title=\"&#x5C3E;&#x9875;\"  data-page=\"'+a.pages+'\">'+(a.last||a.pages)+\"</a>\")),e.join(\"\")}(),next:function(){return a.next?'<a href=\"javascript:;\" class=\"layui-laypage-next'+(a.curr==a.pages?\" \"+r:\"\")+'\" data-page=\"'+(a.curr+1)+'\">'+a.next+\"</a>\":\"\"}(),count:'<span class=\"layui-laypage-count\">共 '+a.count+\" 条</span>\",limit:function(){var e=['<span class=\"layui-laypage-limits\"><select lay-ignore>'];return layui.each(a.limits,function(t,n){e.push('<option value=\"'+n+'\"'+(n===a.limit?\"selected\":\"\")+\">\"+n+\" 条/页</option>\")}),e.join(\"\")+\"</select></span>\"}(),refresh:['<a href=\"javascript:;\" data-page=\"'+a.curr+'\" class=\"layui-laypage-refresh\">','<i class=\"layui-icon layui-icon-refresh\"></i>',\"</a>\"].join(\"\"),skip:function(){return['<span class=\"layui-laypage-skip\">&#x5230;&#x7B2C;','<input type=\"text\" min=\"1\" value=\"'+a.curr+'\" class=\"layui-input\">','&#x9875;<button type=\"button\" class=\"layui-laypage-btn\">&#x786e;&#x5b9a;</button>',\"</span>\"].join(\"\")}()};return['<div class=\"layui-box layui-laypage layui-laypage-'+(a.theme?/^#/.test(a.theme)?\"molv\":a.theme:\"default\")+'\" id=\"layui-laypage-'+a.index+'\">',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join(\"\")}(),\"</div>\"].join(\"\")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n](\"button\")[0],l=e[n](\"input\")[0],p=e[n](\"select\")[0],c=function(){var e=0|l.value.replace(/\\s|\\D/g,\"\");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;o<y;o++)\"a\"===r[o].nodeName.toLowerCase()&&s.on(r[o],\"click\",function(){var e=0|this.getAttribute(\"data-page\");e<1||e>i.pages||(i.curr=e,t.render())});p&&s.on(p,\"change\",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,\"click\",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n](\"input\")[0];t&&s.on(t,\"keyup\",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\\D/.test(n)&&(this.value=n.replace(/\\D/,\"\")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t](\"layui-laypage-\"+i.index);n.jump(s),i.hash&&!e&&(location.hash=\"!\"+i.hash+\"=\"+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent(\"on\"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/laytpl.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(function(e){\"use strict\";var r={open:\"{{\",close:\"}}\"},c={exp:function(e){return new RegExp(e,\"g\")},query:function(e,c,t){var o=[\"#([\\\\s\\\\S])+?\",\"([^{#}])*?\"][e||0];return n((c||\"\")+r.open+o+r.close+(t||\"\"))},escape:function(e){return String(e||\"\").replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")},error:function(e,r){var c=\"Laytpl Error：\";return\"object\"==typeof console&&console.error(c+e+\"\\n\"+(r||\"\")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n(\"^\"+r.open+\"#\",\"\"),l=n(r.close+\"$\",\"\");e=e.replace(/\\s+|\\r|\\t|\\n/g,\" \").replace(n(r.open+\"#\"),r.open+\"# \").replace(n(r.close+\"}\"),\"} \"+r.close).replace(/\\\\/g,\"\\\\\\\\\").replace(n(r.open+\"!(.+?)!\"+r.close),function(e){return e=e.replace(n(\"^\"+r.open+\"!\"),\"\").replace(n(\"!\"+r.close),\"\").replace(n(r.open+\"|\"+r.close),function(e){return e.replace(/(.)/g,\"\\\\$1\")})}).replace(/(?=\"|')/g,\"\\\\\").replace(c.query(),function(e){return e=e.replace(a,\"\").replace(l,\"\"),'\";'+e.replace(/\\\\/g,\"\")+';view+=\"'}).replace(c.query(1),function(e){var c='\"+(';return e.replace(/\\s/g,\"\")===r.open+r.close?\"\":(e=e.replace(n(r.open+\"|\"+r.close),\"\"),/^=/.test(e)&&(e=e.replace(/^=/,\"\"),c='\"+_escape_('),c+e.replace(/\\\\/g,\"\")+')+\"')}),e='\"use strict\";var view = \"'+e+'\";return view;';try{return o.cache=e=new Function(\"d, _escape_\",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error(\"no data\")};var o=function(e){return\"string\"!=typeof e?c.error(\"Template not found\"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v=\"1.2.0\",e(\"laytpl\",o)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/mobile.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(function(i){i(\"layui.mobile\",layui.v)});layui.define(function(e){\"use strict\";var r={open:\"{{\",close:\"}}\"},c={exp:function(e){return new RegExp(e,\"g\")},query:function(e,c,t){var o=[\"#([\\\\s\\\\S])+?\",\"([^{#}])*?\"][e||0];return n((c||\"\")+r.open+o+r.close+(t||\"\"))},escape:function(e){return String(e||\"\").replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")},error:function(e,r){var c=\"Laytpl Error：\";return\"object\"==typeof console&&console.error(c+e+\"\\n\"+(r||\"\")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n(\"^\"+r.open+\"#\",\"\"),l=n(r.close+\"$\",\"\");e=e.replace(/\\s+|\\r|\\t|\\n/g,\" \").replace(n(r.open+\"#\"),r.open+\"# \").replace(n(r.close+\"}\"),\"} \"+r.close).replace(/\\\\/g,\"\\\\\\\\\").replace(n(r.open+\"!(.+?)!\"+r.close),function(e){return e=e.replace(n(\"^\"+r.open+\"!\"),\"\").replace(n(\"!\"+r.close),\"\").replace(n(r.open+\"|\"+r.close),function(e){return e.replace(/(.)/g,\"\\\\$1\")})}).replace(/(?=\"|')/g,\"\\\\\").replace(c.query(),function(e){return e=e.replace(a,\"\").replace(l,\"\"),'\";'+e.replace(/\\\\/g,\"\")+';view+=\"'}).replace(c.query(1),function(e){var c='\"+(';return e.replace(/\\s/g,\"\")===r.open+r.close?\"\":(e=e.replace(n(r.open+\"|\"+r.close),\"\"),/^=/.test(e)&&(e=e.replace(/^=/,\"\"),c='\"+_escape_('),c+e.replace(/\\\\/g,\"\")+')+\"')}),e='\"use strict\";var view = \"'+e+'\";return view;';try{return o.cache=e=new Function(\"d, _escape_\",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error(\"no data\")};var o=function(e){return\"string\"!=typeof e?c.error(\"Template not found\"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v=\"1.2.0\",e(\"laytpl\",o)});layui.define(function(e){\"use strict\";var t=(window,document),i=\"querySelectorAll\",n=\"getElementsByClassName\",a=function(e){return t[i](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:\"scale\"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var i in e)t[i]=e[i];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener(\"click\",function(e){t.call(this,e)},!1)};var o=0,r=[\"layui-m-layer\"],d=function(e){var t=this;t.config=l.extend(e),t.view()};d.prototype.view=function(){var e=this,i=e.config,s=t.createElement(\"div\");e.id=s.id=r[0]+o,s.setAttribute(\"class\",r[0]+\" \"+r[0]+(i.type||0)),s.setAttribute(\"index\",o);var l=function(){var e=\"object\"==typeof i.title;return i.title?'<h3 style=\"'+(e?i.title[1]:\"\")+'\">'+(e?i.title[0]:i.title)+\"</h3>\":\"\"}(),d=function(){\"string\"==typeof i.btn&&(i.btn=[i.btn]);var e,t=(i.btn||[]).length;return 0!==t&&i.btn?(e='<span yes type=\"1\">'+i.btn[0]+\"</span>\",2===t&&(e='<span no type=\"0\">'+i.btn[1]+\"</span>\"+e),'<div class=\"layui-m-layerbtn\">'+e+\"</div>\"):\"\"}();if(i.fixed||(i.top=i.hasOwnProperty(\"top\")?i.top:100,i.style=i.style||\"\",i.style+=\" top:\"+(t.body.scrollTop+i.top)+\"px\"),2===i.type&&(i.content='<i></i><i class=\"layui-m-layerload\"></i><i></i><p>'+(i.content||\"\")+\"</p>\"),i.skin&&(i.anim=\"up\"),\"msg\"===i.skin&&(i.shade=!1),s.innerHTML=(i.shade?\"<div \"+(\"string\"==typeof i.shade?'style=\"'+i.shade+'\"':\"\")+' class=\"layui-m-layershade\"></div>':\"\")+'<div class=\"layui-m-layermain\" '+(i.fixed?\"\":'style=\"position:static;\"')+'><div class=\"layui-m-layersection\"><div class=\"layui-m-layerchild '+(i.skin?\"layui-m-layer-\"+i.skin+\" \":\"\")+(i.className?i.className:\"\")+\" \"+(i.anim?\"layui-m-anim-\"+i.anim:\"\")+'\" '+(i.style?'style=\"'+i.style+'\"':\"\")+\">\"+l+'<div class=\"layui-m-layercont\">'+i.content+\"</div>\"+d+\"</div></div></div>\",!i.type||2===i.type){var y=t[n](r[0]+i.type),u=y.length;u>=1&&c.close(y[0].getAttribute(\"index\"))}document.body.appendChild(s);var m=e.elem=a(\"#\"+e.id)[0];i.success&&i.success(m),e.index=o++,e.action(i,m)},d.prototype.action=function(e,t){var i=this;e.time&&(l.timer[i.index]=setTimeout(function(){c.close(i.index)},1e3*e.time));var a=function(){var t=this.getAttribute(\"type\");0==t?(e.no&&e.no(),c.close(i.index)):e.yes?e.yes(i.index):c.close(i.index)};if(e.btn)for(var s=t[n](\"layui-m-layerbtn\")[0].children,o=s.length,r=0;r<o;r++)l.touch(s[r],a);if(e.shade&&e.shadeClose){var d=t[n](\"layui-m-layershade\")[0];l.touch(d,function(){c.close(i.index,e.end)})}e.end&&(l.end[i.index]=e.end)};var c={v:\"2.0 m\",index:o,open:function(e){var t=new d(e||{});return t.index},close:function(e){var i=a(\"#\"+r[0]+e)[0];i&&(i.innerHTML=\"\",t.body.removeChild(i),clearTimeout(l.timer[e]),delete l.timer[e],\"function\"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[n](r[0]),i=0,a=e.length;i<a;i++)c.close(0|e[0].getAttribute(\"index\"))}};e(\"layer-mobile\",c)});layui.define(function(t){var e=function(){function t(t){return null==t?String(t):J[W.call(t)]||\"object\"}function e(e){return\"function\"==t(e)}function n(t){return null!=t&&t==t.window}function r(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function i(e){return\"object\"==t(e)}function o(t){return i(t)&&!n(t)&&Object.getPrototypeOf(t)==Object.prototype}function a(t){var e=!!t&&\"length\"in t&&t.length,r=T.type(t);return\"function\"!=r&&!n(t)&&(\"array\"==r||0===e||\"number\"==typeof e&&e>0&&e-1 in t)}function s(t){return A.call(t,function(t){return null!=t})}function u(t){return t.length>0?T.fn.concat.apply([],t):t}function c(t){return t.replace(/::/g,\"/\").replace(/([A-Z]+)([A-Z][a-z])/g,\"$1_$2\").replace(/([a-z\\d])([A-Z])/g,\"$1_$2\").replace(/_/g,\"-\").toLowerCase()}function l(t){return t in F?F[t]:F[t]=new RegExp(\"(^|\\\\s)\"+t+\"(\\\\s|$)\")}function f(t,e){return\"number\"!=typeof e||k[c(t)]?e:e+\"px\"}function h(t){var e,n;return $[t]||(e=L.createElement(t),L.body.appendChild(e),n=getComputedStyle(e,\"\").getPropertyValue(\"display\"),e.parentNode.removeChild(e),\"none\"==n&&(n=\"block\"),$[t]=n),$[t]}function p(t){return\"children\"in t?D.call(t.children):T.map(t.childNodes,function(t){if(1==t.nodeType)return t})}function d(t,e){var n,r=t?t.length:0;for(n=0;n<r;n++)this[n]=t[n];this.length=r,this.selector=e||\"\"}function m(t,e,n){for(j in e)n&&(o(e[j])||Q(e[j]))?(o(e[j])&&!o(t[j])&&(t[j]={}),Q(e[j])&&!Q(t[j])&&(t[j]=[]),m(t[j],e[j],n)):e[j]!==E&&(t[j]=e[j])}function v(t,e){return null==e?T(t):T(t).filter(e)}function g(t,n,r,i){return e(n)?n.call(t,r,i):n}function y(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function x(t,e){var n=t.className||\"\",r=n&&n.baseVal!==E;return e===E?r?n.baseVal:n:void(r?n.baseVal=e:t.className=e)}function b(t){try{return t?\"true\"==t||\"false\"!=t&&(\"null\"==t?null:+t+\"\"==t?+t:/^[\\[\\{]/.test(t)?T.parseJSON(t):t):t}catch(e){return t}}function w(t,e){e(t);for(var n=0,r=t.childNodes.length;n<r;n++)w(t.childNodes[n],e)}var E,j,T,S,C,N,O=[],P=O.concat,A=O.filter,D=O.slice,L=window.document,$={},F={},k={\"column-count\":1,columns:1,\"font-weight\":1,\"line-height\":1,opacity:1,\"z-index\":1,zoom:1},M=/^\\s*<(\\w+|!)[^>]*>/,R=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,Z=/^(?:body|html)$/i,q=/([A-Z])/g,H=[\"val\",\"css\",\"html\",\"text\",\"data\",\"width\",\"height\",\"offset\"],I=[\"after\",\"prepend\",\"before\",\"append\"],V=L.createElement(\"table\"),_=L.createElement(\"tr\"),B={tr:L.createElement(\"tbody\"),tbody:V,thead:V,tfoot:V,td:_,th:_,\"*\":L.createElement(\"div\")},U=/complete|loaded|interactive/,X=/^[\\w-]*$/,J={},W=J.toString,Y={},G=L.createElement(\"div\"),K={tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},Q=Array.isArray||function(t){return t instanceof Array};return Y.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var r,i=t.parentNode,o=!i;return o&&(i=G).appendChild(t),r=~Y.qsa(i,e).indexOf(t),o&&G.removeChild(t),r},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():\"\"})},N=function(t){return A.call(t,function(e,n){return t.indexOf(e)==n})},Y.fragment=function(t,e,n){var r,i,a;return R.test(t)&&(r=T(L.createElement(RegExp.$1))),r||(t.replace&&(t=t.replace(z,\"<$1></$2>\")),e===E&&(e=M.test(t)&&RegExp.$1),e in B||(e=\"*\"),a=B[e],a.innerHTML=\"\"+t,r=T.each(D.call(a.childNodes),function(){a.removeChild(this)})),o(n)&&(i=T(r),T.each(n,function(t,e){H.indexOf(t)>-1?i[t](e):i.attr(t,e)})),r},Y.Z=function(t,e){return new d(t,e)},Y.isZ=function(t){return t instanceof Y.Z},Y.init=function(t,n){var r;if(!t)return Y.Z();if(\"string\"==typeof t)if(t=t.trim(),\"<\"==t[0]&&M.test(t))r=Y.fragment(t,RegExp.$1,n),t=null;else{if(n!==E)return T(n).find(t);r=Y.qsa(L,t)}else{if(e(t))return T(L).ready(t);if(Y.isZ(t))return t;if(Q(t))r=s(t);else if(i(t))r=[t],t=null;else if(M.test(t))r=Y.fragment(t.trim(),RegExp.$1,n),t=null;else{if(n!==E)return T(n).find(t);r=Y.qsa(L,t)}}return Y.Z(r,t)},T=function(t,e){return Y.init(t,e)},T.extend=function(t){var e,n=D.call(arguments,1);return\"boolean\"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){m(t,n,e)}),t},Y.qsa=function(t,e){var n,r=\"#\"==e[0],i=!r&&\".\"==e[0],o=r||i?e.slice(1):e,a=X.test(o);return t.getElementById&&a&&r?(n=t.getElementById(o))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:D.call(a&&!r&&t.getElementsByClassName?i?t.getElementsByClassName(o):t.getElementsByTagName(e):t.querySelectorAll(e))},T.contains=L.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},T.type=t,T.isFunction=e,T.isWindow=n,T.isArray=Q,T.isPlainObject=o,T.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},T.isNumeric=function(t){var e=Number(t),n=typeof t;return null!=t&&\"boolean\"!=n&&(\"string\"!=n||t.length)&&!isNaN(e)&&isFinite(e)||!1},T.inArray=function(t,e,n){return O.indexOf.call(e,t,n)},T.camelCase=C,T.trim=function(t){return null==t?\"\":String.prototype.trim.call(t)},T.uuid=0,T.support={},T.expr={},T.noop=function(){},T.map=function(t,e){var n,r,i,o=[];if(a(t))for(r=0;r<t.length;r++)n=e(t[r],r),null!=n&&o.push(n);else for(i in t)n=e(t[i],i),null!=n&&o.push(n);return u(o)},T.each=function(t,e){var n,r;if(a(t)){for(n=0;n<t.length;n++)if(e.call(t[n],n,t[n])===!1)return t}else for(r in t)if(e.call(t[r],r,t[r])===!1)return t;return t},T.grep=function(t,e){return A.call(t,e)},window.JSON&&(T.parseJSON=JSON.parse),T.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"),function(t,e){J[\"[object \"+e+\"]\"]=e.toLowerCase()}),T.fn={constructor:Y.Z,length:0,forEach:O.forEach,reduce:O.reduce,push:O.push,sort:O.sort,splice:O.splice,indexOf:O.indexOf,concat:function(){var t,e,n=[];for(t=0;t<arguments.length;t++)e=arguments[t],n[t]=Y.isZ(e)?e.toArray():e;return P.apply(Y.isZ(this)?this.toArray():this,n)},map:function(t){return T(T.map(this,function(e,n){return t.call(e,n,e)}))},slice:function(){return T(D.apply(this,arguments))},ready:function(t){return U.test(L.readyState)&&L.body?t(T):L.addEventListener(\"DOMContentLoaded\",function(){t(T)},!1),this},get:function(t){return t===E?D.call(this):this[t>=0?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return O.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return e(t)?this.not(this.not(t)):T(A.call(this,function(e){return Y.matches(e,t)}))},add:function(t,e){return T(N(this.concat(T(t,e))))},is:function(t){return this.length>0&&Y.matches(this[0],t)},not:function(t){var n=[];if(e(t)&&t.call!==E)this.each(function(e){t.call(this,e)||n.push(this)});else{var r=\"string\"==typeof t?this.filter(t):a(t)&&e(t.item)?D.call(t):T(t);this.forEach(function(t){r.indexOf(t)<0&&n.push(t)})}return T(n)},has:function(t){return this.filter(function(){return i(t)?T.contains(this,t):T(this).find(t).size()})},eq:function(t){return t===-1?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!i(t)?t:T(t)},last:function(){var t=this[this.length-1];return t&&!i(t)?t:T(t)},find:function(t){var e,n=this;return e=t?\"object\"==typeof t?T(t).filter(function(){var t=this;return O.some.call(n,function(e){return T.contains(e,t)})}):1==this.length?T(Y.qsa(this[0],t)):this.map(function(){return Y.qsa(this,t)}):T()},closest:function(t,e){var n=[],i=\"object\"==typeof t&&T(t);return this.each(function(o,a){for(;a&&!(i?i.indexOf(a)>=0:Y.matches(a,t));)a=a!==e&&!r(a)&&a.parentNode;a&&n.indexOf(a)<0&&n.push(a)}),T(n)},parents:function(t){for(var e=[],n=this;n.length>0;)n=T.map(n,function(t){if((t=t.parentNode)&&!r(t)&&e.indexOf(t)<0)return e.push(t),t});return v(e,t)},parent:function(t){return v(N(this.pluck(\"parentNode\")),t)},children:function(t){return v(this.map(function(){return p(this)}),t)},contents:function(){return this.map(function(){return this.contentDocument||D.call(this.childNodes)})},siblings:function(t){return v(this.map(function(t,e){return A.call(p(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=\"\"})},pluck:function(t){return T.map(this,function(e){return e[t]})},show:function(){return this.each(function(){\"none\"==this.style.display&&(this.style.display=\"\"),\"none\"==getComputedStyle(this,\"\").getPropertyValue(\"display\")&&(this.style.display=h(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var n=e(t);if(this[0]&&!n)var r=T(t).get(0),i=r.parentNode||this.length>1;return this.each(function(e){T(this).wrapAll(n?t.call(this,e):i?r.cloneNode(!0):r)})},wrapAll:function(t){if(this[0]){T(this[0]).before(t=T(t));for(var e;(e=t.children()).length;)t=e.first();T(t).append(this)}return this},wrapInner:function(t){var n=e(t);return this.each(function(e){var r=T(this),i=r.contents(),o=n?t.call(this,e):t;i.length?i.wrapAll(o):r.append(o)})},unwrap:function(){return this.parent().each(function(){T(this).replaceWith(T(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css(\"display\",\"none\")},toggle:function(t){return this.each(function(){var e=T(this);(t===E?\"none\"==e.css(\"display\"):t)?e.show():e.hide()})},prev:function(t){return T(this.pluck(\"previousElementSibling\")).filter(t||\"*\")},next:function(t){return T(this.pluck(\"nextElementSibling\")).filter(t||\"*\")},html:function(t){return 0 in arguments?this.each(function(e){var n=this.innerHTML;T(this).empty().append(g(this,t,e,n))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=g(this,t,e,this.textContent);this.textContent=null==n?\"\":\"\"+n}):0 in this?this.pluck(\"textContent\").join(\"\"):null},attr:function(t,e){var n;return\"string\"!=typeof t||1 in arguments?this.each(function(n){if(1===this.nodeType)if(i(t))for(j in t)y(this,j,t[j]);else y(this,t,g(this,e,n,this.getAttribute(t)))}):0 in this&&1==this[0].nodeType&&null!=(n=this[0].getAttribute(t))?n:E},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(\" \").forEach(function(t){y(this,t)},this)})},prop:function(t,e){return t=K[t]||t,1 in arguments?this.each(function(n){this[t]=g(this,e,n,this[t])}):this[0]&&this[0][t]},removeProp:function(t){return t=K[t]||t,this.each(function(){delete this[t]})},data:function(t,e){var n=\"data-\"+t.replace(q,\"-$1\").toLowerCase(),r=1 in arguments?this.attr(n,e):this.attr(n);return null!==r?b(r):E},val:function(t){return 0 in arguments?(null==t&&(t=\"\"),this.each(function(e){this.value=g(this,t,e,this.value)})):this[0]&&(this[0].multiple?T(this[0]).find(\"option\").filter(function(){return this.selected}).pluck(\"value\"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var n=T(this),r=g(this,t,e,n.offset()),i=n.offsetParent().offset(),o={top:r.top-i.top,left:r.left-i.left};\"static\"==n.css(\"position\")&&(o.position=\"relative\"),n.css(o)});if(!this.length)return null;if(L.documentElement!==this[0]&&!T.contains(L.documentElement,this[0]))return{top:0,left:0};var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(e,n){if(arguments.length<2){var r=this[0];if(\"string\"==typeof e){if(!r)return;return r.style[C(e)]||getComputedStyle(r,\"\").getPropertyValue(e)}if(Q(e)){if(!r)return;var i={},o=getComputedStyle(r,\"\");return T.each(e,function(t,e){i[e]=r.style[C(e)]||o.getPropertyValue(e)}),i}}var a=\"\";if(\"string\"==t(e))n||0===n?a=c(e)+\":\"+f(e,n):this.each(function(){this.style.removeProperty(c(e))});else for(j in e)e[j]||0===e[j]?a+=c(j)+\":\"+f(j,e[j])+\";\":this.each(function(){this.style.removeProperty(c(j))});return this.each(function(){this.style.cssText+=\";\"+a})},index:function(t){return t?this.indexOf(T(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return!!t&&O.some.call(this,function(t){return this.test(x(t))},l(t))},addClass:function(t){return t?this.each(function(e){if(\"className\"in this){S=[];var n=x(this),r=g(this,t,e,n);r.split(/\\s+/g).forEach(function(t){T(this).hasClass(t)||S.push(t)},this),S.length&&x(this,n+(n?\" \":\"\")+S.join(\" \"))}}):this},removeClass:function(t){return this.each(function(e){if(\"className\"in this){if(t===E)return x(this,\"\");S=x(this),g(this,t,e,S).split(/\\s+/g).forEach(function(t){S=S.replace(l(t),\" \")}),x(this,S.trim())}})},toggleClass:function(t,e){return t?this.each(function(n){var r=T(this),i=g(this,t,n,x(this));i.split(/\\s+/g).forEach(function(t){(e===E?!r.hasClass(t):e)?r.addClass(t):r.removeClass(t)})}):this},scrollTop:function(t){if(this.length){var e=\"scrollTop\"in this[0];return t===E?e?this[0].scrollTop:this[0].pageYOffset:this.each(e?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var e=\"scrollLeft\"in this[0];return t===E?e?this[0].scrollLeft:this[0].pageXOffset:this.each(e?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),n=this.offset(),r=Z.test(e[0].nodeName)?{top:0,left:0}:e.offset();return n.top-=parseFloat(T(t).css(\"margin-top\"))||0,n.left-=parseFloat(T(t).css(\"margin-left\"))||0,r.top+=parseFloat(T(e[0]).css(\"border-top-width\"))||0,r.left+=parseFloat(T(e[0]).css(\"border-left-width\"))||0,{top:n.top-r.top,left:n.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||L.body;t&&!Z.test(t.nodeName)&&\"static\"==T(t).css(\"position\");)t=t.offsetParent;return t})}},T.fn.detach=T.fn.remove,[\"width\",\"height\"].forEach(function(t){var e=t.replace(/./,function(t){return t[0].toUpperCase()});T.fn[t]=function(i){var o,a=this[0];return i===E?n(a)?a[\"inner\"+e]:r(a)?a.documentElement[\"scroll\"+e]:(o=this.offset())&&o[t]:this.each(function(e){a=T(this),a.css(t,g(this,i,e,a[t]()))})}}),I.forEach(function(e,n){var r=n%2;T.fn[e]=function(){var e,i,o=T.map(arguments,function(n){var r=[];return e=t(n),\"array\"==e?(n.forEach(function(t){return t.nodeType!==E?r.push(t):T.zepto.isZ(t)?r=r.concat(t.get()):void(r=r.concat(Y.fragment(t)))}),r):\"object\"==e||null==n?n:Y.fragment(n)}),a=this.length>1;return o.length<1?this:this.each(function(t,e){i=r?e:e.parentNode,e=0==n?e.nextSibling:1==n?e.firstChild:2==n?e:null;var s=T.contains(L.documentElement,i);o.forEach(function(t){if(a)t=t.cloneNode(!0);else if(!i)return T(t).remove();i.insertBefore(t,e),s&&w(t,function(t){if(!(null==t.nodeName||\"SCRIPT\"!==t.nodeName.toUpperCase()||t.type&&\"text/javascript\"!==t.type||t.src)){var e=t.ownerDocument?t.ownerDocument.defaultView:window;e.eval.call(e,t.innerHTML)}})})})},T.fn[r?e+\"To\":\"insert\"+(n?\"Before\":\"After\")]=function(t){return T(t)[e](this),this}}),Y.Z.prototype=d.prototype=T.fn,Y.uniq=N,Y.deserializeValue=b,T.zepto=Y,T}();!function(t){function e(t){return t._zid||(t._zid=h++)}function n(t,n,o,a){if(n=r(n),n.ns)var s=i(n.ns);return(v[e(t)]||[]).filter(function(t){return t&&(!n.e||t.e==n.e)&&(!n.ns||s.test(t.ns))&&(!o||e(t.fn)===e(o))&&(!a||t.sel==a)})}function r(t){var e=(\"\"+t).split(\".\");return{e:e[0],ns:e.slice(1).sort().join(\" \")}}function i(t){return new RegExp(\"(?:^| )\"+t.replace(\" \",\" .* ?\")+\"(?: |$)\")}function o(t,e){return t.del&&!y&&t.e in x||!!e}function a(t){return b[t]||y&&x[t]||t}function s(n,i,s,u,l,h,p){var d=e(n),m=v[d]||(v[d]=[]);i.split(/\\s/).forEach(function(e){if(\"ready\"==e)return t(document).ready(s);var i=r(e);i.fn=s,i.sel=l,i.e in b&&(s=function(e){var n=e.relatedTarget;if(!n||n!==this&&!t.contains(this,n))return i.fn.apply(this,arguments)}),i.del=h;var d=h||s;i.proxy=function(t){if(t=c(t),!t.isImmediatePropagationStopped()){t.data=u;var e=d.apply(n,t._args==f?[t]:[t].concat(t._args));return e===!1&&(t.preventDefault(),t.stopPropagation()),e}},i.i=m.length,m.push(i),\"addEventListener\"in n&&n.addEventListener(a(i.e),i.proxy,o(i,p))})}function u(t,r,i,s,u){var c=e(t);(r||\"\").split(/\\s/).forEach(function(e){n(t,e,i,s).forEach(function(e){delete v[c][e.i],\"removeEventListener\"in t&&t.removeEventListener(a(e.e),e.proxy,o(e,u))})})}function c(e,n){return!n&&e.isDefaultPrevented||(n||(n=e),t.each(T,function(t,r){var i=n[t];e[t]=function(){return this[r]=w,i&&i.apply(n,arguments)},e[r]=E}),e.timeStamp||(e.timeStamp=Date.now()),(n.defaultPrevented!==f?n.defaultPrevented:\"returnValue\"in n?n.returnValue===!1:n.getPreventDefault&&n.getPreventDefault())&&(e.isDefaultPrevented=w)),e}function l(t){var e,n={originalEvent:t};for(e in t)j.test(e)||t[e]===f||(n[e]=t[e]);return c(n,t)}var f,h=1,p=Array.prototype.slice,d=t.isFunction,m=function(t){return\"string\"==typeof t},v={},g={},y=\"onfocusin\"in window,x={focus:\"focusin\",blur:\"focusout\"},b={mouseenter:\"mouseover\",mouseleave:\"mouseout\"};g.click=g.mousedown=g.mouseup=g.mousemove=\"MouseEvents\",t.event={add:s,remove:u},t.proxy=function(n,r){var i=2 in arguments&&p.call(arguments,2);if(d(n)){var o=function(){return n.apply(r,i?i.concat(p.call(arguments)):arguments)};return o._zid=e(n),o}if(m(r))return i?(i.unshift(n[r],n),t.proxy.apply(null,i)):t.proxy(n[r],n);throw new TypeError(\"expected function\")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,r){return this.on(t,e,n,r,1)};var w=function(){return!0},E=function(){return!1},j=/^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,T={preventDefault:\"isDefaultPrevented\",stopImmediatePropagation:\"isImmediatePropagationStopped\",stopPropagation:\"isPropagationStopped\"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,n,r,i,o){var a,c,h=this;return e&&!m(e)?(t.each(e,function(t,e){h.on(t,n,r,e,o)}),h):(m(n)||d(i)||i===!1||(i=r,r=n,n=f),i!==f&&r!==!1||(i=r,r=f),i===!1&&(i=E),h.each(function(f,h){o&&(a=function(t){return u(h,t.type,i),i.apply(this,arguments)}),n&&(c=function(e){var r,o=t(e.target).closest(n,h).get(0);if(o&&o!==h)return r=t.extend(l(e),{currentTarget:o,liveFired:h}),(a||i).apply(o,[r].concat(p.call(arguments,1)))}),s(h,e,i,r,n,c||a)}))},t.fn.off=function(e,n,r){var i=this;return e&&!m(e)?(t.each(e,function(t,e){i.off(t,n,e)}),i):(m(n)||d(r)||r===!1||(r=n,n=f),r===!1&&(r=E),i.each(function(){u(this,e,r,n)}))},t.fn.trigger=function(e,n){return e=m(e)||t.isPlainObject(e)?t.Event(e):c(e),e._args=n,this.each(function(){e.type in x&&\"function\"==typeof this[e.type]?this[e.type]():\"dispatchEvent\"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,r){var i,o;return this.each(function(a,s){i=l(m(e)?t.Event(e):e),i._args=r,i.target=s,t.each(n(s,e.type||e),function(t,e){if(o=e.proxy(i),i.isImmediatePropagationStopped())return!1})}),o},\"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error\".split(\" \").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){m(t)||(e=t,t=e.type);var n=document.createEvent(g[t]||\"Events\"),r=!0;if(e)for(var i in e)\"bubbles\"==i?r=!!e[i]:n[i]=e[i];return n.initEvent(t,r,!0),c(n)}}(e),function(t){function e(e,n,r){var i=t.Event(n);return t(e).trigger(i,r),!i.isDefaultPrevented()}function n(t,n,r,i){if(t.global)return e(n||x,r,i)}function r(e){e.global&&0===t.active++&&n(e,null,\"ajaxStart\")}function i(e){e.global&&!--t.active&&n(e,null,\"ajaxStop\")}function o(t,e){var r=e.context;return e.beforeSend.call(r,t,e)!==!1&&n(e,r,\"ajaxBeforeSend\",[t,e])!==!1&&void n(e,r,\"ajaxSend\",[t,e])}function a(t,e,r,i){var o=r.context,a=\"success\";r.success.call(o,t,a,e),i&&i.resolveWith(o,[t,a,e]),n(r,o,\"ajaxSuccess\",[e,r,t]),u(a,e,r)}function s(t,e,r,i,o){var a=i.context;i.error.call(a,r,e,t),o&&o.rejectWith(a,[r,e,t]),n(i,a,\"ajaxError\",[r,i,t||e]),u(e,r,i)}function u(t,e,r){var o=r.context;r.complete.call(o,e,t),n(r,o,\"ajaxComplete\",[e,r]),i(r)}function c(t,e,n){if(n.dataFilter==l)return t;var r=n.context;return n.dataFilter.call(r,t,e)}function l(){}function f(t){return t&&(t=t.split(\";\",2)[0]),t&&(t==T?\"html\":t==j?\"json\":w.test(t)?\"script\":E.test(t)&&\"xml\")||\"text\"}function h(t,e){return\"\"==e?t:(t+\"&\"+e).replace(/[&?]{1,2}/,\"?\")}function p(e){e.processData&&e.data&&\"string\"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&\"GET\"!=e.type.toUpperCase()&&\"jsonp\"!=e.dataType||(e.url=h(e.url,e.data),e.data=void 0)}function d(e,n,r,i){return t.isFunction(n)&&(i=r,r=n,n=void 0),t.isFunction(r)||(i=r,r=void 0),{url:e,data:n,success:r,dataType:i}}function m(e,n,r,i){var o,a=t.isArray(n),s=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),i&&(n=r?i:i+\"[\"+(s||\"object\"==o||\"array\"==o?n:\"\")+\"]\"),!i&&a?e.add(u.name,u.value):\"array\"==o||!r&&\"object\"==o?m(e,u,r,n):e.add(n,u)})}var v,g,y=+new Date,x=window.document,b=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,w=/^(?:text|application)\\/javascript/i,E=/^(?:text|application)\\/xml/i,j=\"application/json\",T=\"text/html\",S=/^\\s*$/,C=x.createElement(\"a\");C.href=window.location.href,t.active=0,t.ajaxJSONP=function(e,n){if(!(\"type\"in e))return t.ajax(e);var r,i,u=e.jsonpCallback,c=(t.isFunction(u)?u():u)||\"Zepto\"+y++,l=x.createElement(\"script\"),f=window[c],h=function(e){t(l).triggerHandler(\"error\",e||\"abort\")},p={abort:h};return n&&n.promise(p),t(l).on(\"load error\",function(o,u){clearTimeout(i),t(l).off().remove(),\"error\"!=o.type&&r?a(r[0],p,e,n):s(null,u||\"error\",p,e,n),window[c]=f,r&&t.isFunction(f)&&f(r[0]),f=r=void 0}),o(p,e)===!1?(h(\"abort\"),p):(window[c]=function(){r=arguments},l.src=e.url.replace(/\\?(.+)=\\?/,\"?$1=\"+c),x.head.appendChild(l),e.timeout>0&&(i=setTimeout(function(){h(\"timeout\")},e.timeout)),p)},t.ajaxSettings={type:\"GET\",beforeSend:l,success:l,error:l,complete:l,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:\"text/javascript, application/javascript, application/x-javascript\",json:j,xml:\"application/xml, text/xml\",html:T,text:\"text/plain\"},crossDomain:!1,timeout:0,processData:!0,cache:!0,dataFilter:l},t.ajax=function(e){var n,i,u=t.extend({},e||{}),d=t.Deferred&&t.Deferred();for(v in t.ajaxSettings)void 0===u[v]&&(u[v]=t.ajaxSettings[v]);r(u),u.crossDomain||(n=x.createElement(\"a\"),n.href=u.url,n.href=n.href,u.crossDomain=C.protocol+\"//\"+C.host!=n.protocol+\"//\"+n.host),u.url||(u.url=window.location.toString()),(i=u.url.indexOf(\"#\"))>-1&&(u.url=u.url.slice(0,i)),p(u);var m=u.dataType,y=/\\?.+=\\?/.test(u.url);if(y&&(m=\"jsonp\"),u.cache!==!1&&(e&&e.cache===!0||\"script\"!=m&&\"jsonp\"!=m)||(u.url=h(u.url,\"_=\"+Date.now())),\"jsonp\"==m)return y||(u.url=h(u.url,u.jsonp?u.jsonp+\"=?\":u.jsonp===!1?\"\":\"callback=?\")),t.ajaxJSONP(u,d);var b,w=u.accepts[m],E={},j=function(t,e){E[t.toLowerCase()]=[t,e]},T=/^([\\w-]+:)\\/\\//.test(u.url)?RegExp.$1:window.location.protocol,N=u.xhr(),O=N.setRequestHeader;if(d&&d.promise(N),u.crossDomain||j(\"X-Requested-With\",\"XMLHttpRequest\"),j(\"Accept\",w||\"*/*\"),(w=u.mimeType||w)&&(w.indexOf(\",\")>-1&&(w=w.split(\",\",2)[0]),N.overrideMimeType&&N.overrideMimeType(w)),(u.contentType||u.contentType!==!1&&u.data&&\"GET\"!=u.type.toUpperCase())&&j(\"Content-Type\",u.contentType||\"application/x-www-form-urlencoded\"),u.headers)for(g in u.headers)j(g,u.headers[g]);if(N.setRequestHeader=j,N.onreadystatechange=function(){if(4==N.readyState){N.onreadystatechange=l,clearTimeout(b);var e,n=!1;if(N.status>=200&&N.status<300||304==N.status||0==N.status&&\"file:\"==T){if(m=m||f(u.mimeType||N.getResponseHeader(\"content-type\")),\"arraybuffer\"==N.responseType||\"blob\"==N.responseType)e=N.response;else{e=N.responseText;try{e=c(e,m,u),\"script\"==m?(0,eval)(e):\"xml\"==m?e=N.responseXML:\"json\"==m&&(e=S.test(e)?null:t.parseJSON(e))}catch(r){n=r}if(n)return s(n,\"parsererror\",N,u,d)}a(e,N,u,d)}else s(N.statusText||null,N.status?\"error\":\"abort\",N,u,d)}},o(N,u)===!1)return N.abort(),s(null,\"abort\",N,u,d),N;var P=!(\"async\"in u)||u.async;if(N.open(u.type,u.url,P,u.username,u.password),u.xhrFields)for(g in u.xhrFields)N[g]=u.xhrFields[g];for(g in E)O.apply(N,E[g]);return u.timeout>0&&(b=setTimeout(function(){N.onreadystatechange=l,N.abort(),s(null,\"timeout\",N,u,d)},u.timeout)),N.send(u.data?u.data:null),N},t.get=function(){return t.ajax(d.apply(null,arguments))},t.post=function(){var e=d.apply(null,arguments);return e.type=\"POST\",t.ajax(e)},t.getJSON=function(){var e=d.apply(null,arguments);return e.dataType=\"json\",t.ajax(e)},t.fn.load=function(e,n,r){if(!this.length)return this;var i,o=this,a=e.split(/\\s/),s=d(e,n,r),u=s.success;return a.length>1&&(s.url=a[0],i=a[1]),s.success=function(e){o.html(i?t(\"<div>\").html(e.replace(b,\"\")).find(i):e),u&&u.apply(o,arguments)},t.ajax(s),this};var N=encodeURIComponent;t.param=function(e,n){var r=[];return r.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=\"\"),this.push(N(e)+\"=\"+N(n))},m(r,e,n),r.join(\"&\").replace(/%20/g,\"+\")}}(e),function(t){t.fn.serializeArray=function(){var e,n,r=[],i=function(t){return t.forEach?t.forEach(i):void r.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(r,o){n=o.type,e=o.name,e&&\"fieldset\"!=o.nodeName.toLowerCase()&&!o.disabled&&\"submit\"!=n&&\"reset\"!=n&&\"button\"!=n&&\"file\"!=n&&(\"radio\"!=n&&\"checkbox\"!=n||o.checked)&&i(t(o).val())}),r},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+\"=\"+encodeURIComponent(e.value))}),t.join(\"&\")},t.fn.submit=function(e){if(0 in arguments)this.bind(\"submit\",e);else if(this.length){var n=t.Event(\"submit\");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(e),function(){try{getComputedStyle(void 0)}catch(t){var e=getComputedStyle;window.getComputedStyle=function(t,n){try{return e(t,n)}catch(r){return null}}}}(),t(\"zepto\",e)});layui.define([\"layer-mobile\",\"zepto\"],function(e){\"use strict\";var t=layui.zepto,a=layui[\"layer-mobile\"],i=(layui.device(),\"layui-upload-enter\"),n=\"layui-upload-iframe\",r={icon:2,shift:6},o={file:\"文件\",video:\"视频\",audio:\"音频\"};a.msg=function(e){return a.open({content:e||\"\",skin:\"msg\",time:2})};var s=function(e){this.options=e};s.prototype.init=function(){var e=this,a=e.options,r=t(\"body\"),s=t(a.elem||\".layui-upload-file\"),u=t('<iframe id=\"'+n+'\" class=\"'+n+'\" name=\"'+n+'\"></iframe>');return t(\"#\"+n)[0]||r.append(u),s.each(function(r,s){s=t(s);var u='<form target=\"'+n+'\" method=\"'+(a.method||\"post\")+'\" key=\"set-mine\" enctype=\"multipart/form-data\" action=\"'+(a.url||\"\")+'\"></form>',l=s.attr(\"lay-type\")||a.type;a.unwrap||(u='<div class=\"layui-box layui-upload-button\">'+u+'<span class=\"layui-upload-icon\"><i class=\"layui-icon\">&#xe608;</i>'+(s.attr(\"lay-title\")||a.title||\"上传\"+(o[l]||\"图片\"))+\"</span></div>\"),u=t(u),a.unwrap||u.on(\"dragover\",function(e){e.preventDefault(),t(this).addClass(i)}).on(\"dragleave\",function(){t(this).removeClass(i)}).on(\"drop\",function(){t(this).removeClass(i)}),s.parent(\"form\").attr(\"target\")===n&&(a.unwrap?s.unwrap():(s.parent().next().remove(),s.unwrap().unwrap())),s.wrap(u),s.off(\"change\").on(\"change\",function(){e.action(this,l)})})},s.prototype.action=function(e,i){var o=this,s=o.options,u=e.value,l=t(e),p=l.attr(\"lay-ext\")||s.ext||\"\";if(u){switch(i){case\"file\":if(p&&!RegExp(\"\\\\w\\\\.(\"+p+\")$\",\"i\").test(escape(u)))return a.msg(\"不支持该文件格式\",r),e.value=\"\";break;case\"video\":if(!RegExp(\"\\\\w\\\\.(\"+(p||\"avi|mp4|wma|rmvb|rm|flash|3gp|flv\")+\")$\",\"i\").test(escape(u)))return a.msg(\"不支持该视频格式\",r),e.value=\"\";break;case\"audio\":if(!RegExp(\"\\\\w\\\\.(\"+(p||\"mp3|wav|mid\")+\")$\",\"i\").test(escape(u)))return a.msg(\"不支持该音频格式\",r),e.value=\"\";break;default:if(!RegExp(\"\\\\w\\\\.(\"+(p||\"jpg|png|gif|bmp|jpeg\")+\")$\",\"i\").test(escape(u)))return a.msg(\"不支持该图片格式\",r),e.value=\"\"}s.before&&s.before(e),l.parent().submit();var c=t(\"#\"+n),f=setInterval(function(){var t;try{t=c.contents().find(\"body\").text()}catch(i){a.msg(\"上传接口存在跨域\",r),clearInterval(f)}if(t){clearInterval(f),c.contents().find(\"body\").html(\"\");try{t=JSON.parse(t)}catch(i){return t={},a.msg(\"请对上传接口返回JSON字符\",r)}\"function\"==typeof s.success&&s.success(t,e)}},30);e.value=\"\"}},e(\"upload-mobile\",function(e){var t=new s(e=e||{});t.init()})});layui.define(function(i){i(\"layim-mobile\",layui.v)});layui[\"layui.mobile\"]||layui.config({base:layui.cache.dir+\"lay/modules/mobile/\"}).extend({\"layer-mobile\":\"layer-mobile\",zepto:\"zepto\",\"upload-mobile\":\"upload-mobile\",\"layim-mobile\":\"layim-mobile\"}),layui.define([\"layer-mobile\",\"zepto\",\"layim-mobile\"],function(l){l(\"mobile\",{layer:layui[\"layer-mobile\"],layim:layui[\"layim-mobile\"]})});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/rate.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(e){\"use strict\";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n=\"rate\",t=\"layui-rate\",o=\"layui-icon-rate\",s=\"layui-icon-rate-solid\",u=\"layui-icon-rate-half\",r=\"layui-icon-rate-solid layui-icon-rate-half\",c=\"layui-icon-rate-solid layui-icon-rate\",f=\"layui-icon-rate layui-icon-rate-half\",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:\"\"},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style=\"color: '+i.theme+';\"':\"\";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='<ul class=\"layui-rate\" '+(i.readonly?\"readonly\":\"\")+\">\",u=1;u<=i.length;u++){var r='<li class=\"layui-inline\"><i class=\"layui-icon '+(u>Math.floor(i.value)?o:s)+'\" '+l+\"></i></li>\";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'<li><i class=\"layui-icon layui-icon-rate-half\" '+l+\"></i></li>\":n+=r}n+=\"</ul>\"+(i.text?'<span class=\"layui-inline\">'+i.value+\"星\":\"\")+\"</span>\";var c=i.elem,f=c.next(\".\"+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next(\"span\"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass(\"layui-inline\"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find(\"i\").width();l.children(\"li\").each(function(e){var t=e+1,v=a(this);v.on(\"click\",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next(\"span\").text(i.value+\"星\"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on(\"mousemove\",function(e){if(l.find(\"i\").each(function(){a(this).addClass(o).removeClass(r)}),l.find(\"i:lt(\"+t+\")\").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children(\"i\").addClass(u).removeClass(s)}}),v.on(\"mouseleave\",function(){l.find(\"i\").each(function(){a(this).addClass(o).removeClass(r)}),l.find(\"i:lt(\"+Math.floor(i.value)+\")\").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children(\"li:eq(\"+Math.floor(i.value)+\")\").children(\"i\").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/slider.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(e){\"use strict\";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(i,t){return e.slide(\"set\",i,t||0)},config:i}},n=\"slider\",l=\"layui-disabled\",s=\"layui-slider\",r=\"layui-slider-bar\",o=\"layui-slider-wrap\",u=\"layui-slider-wrap-btn\",d=\"layui-slider-tips\",v=\"layui-slider-input\",c=\"layui-slider-input-txt\",m=\"layui-slider-input-btn\",p=\"layui-slider-hover\",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.prototype.config={type:\"default\",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:\"#009688\"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.max<t.min&&(t.max=t.min+t.step),t.range){t.value=\"object\"==typeof t.value?t.value:[t.min,t.value];var a=Math.min(t.value[0],t.value[1]),n=Math.max(t.value[0],t.value[1]);t.value[0]=a>t.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+\"%\";r+=\"%\",v+=\"%\"}else{\"object\"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.value<t.min&&(t.value=t.min),t.value>t.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+\"%\"}var p=t.disabled?\"#c2c2c2\":t.theme,f='<div class=\"layui-slider '+(\"vertical\"===t.type?\"layui-slider-vertical\":\"\")+'\">'+(t.tips?'<div class=\"layui-slider-tips\"></div>':\"\")+'<div class=\"layui-slider-bar\" style=\"background:'+p+\"; \"+(\"vertical\"===t.type?\"height\":\"width\")+\":\"+m+\";\"+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+(r||0)+';\"></div><div class=\"layui-slider-wrap\" style=\"'+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+(r||m)+';\"><div class=\"layui-slider-wrap-btn\" style=\"border: 2px solid '+p+';\"></div></div>'+(t.range?'<div class=\"layui-slider-wrap\" style=\"'+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+v+';\"><div class=\"layui-slider-wrap-btn\" style=\"border: 2px solid '+p+';\"></div></div>':\"\")+\"</div>\",h=i(t.elem),y=h.next(\".\"+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find(\".\"+o).eq(0).data(\"value\",t.value[0]),e.elemTemp.find(\".\"+o).eq(1).data(\"value\",t.value[1])):e.elemTemp.find(\".\"+o).data(\"value\",t.value),h.html(e.elemTemp),\"vertical\"===t.type&&e.elemTemp.height(t.height+\"px\"),t.showstep){for(var g=(t.max-t.min)/t.step,b=\"\",x=1;x<g+1;x++){var T=100*x/g;T<100&&(b+='<div class=\"layui-slider-step\" style=\"'+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+T+'%\"></div>')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('<div class=\"layui-slider-input layui-input\"><div class=\"layui-slider-input-txt\"><input type=\"text\" class=\"layui-input\"></div><div class=\"layui-slider-input-btn\"><i class=\"layui-icon layui-icon-up\"></i><i class=\"layui-icon layui-icon-down\"></i></div></div>');h.css(\"position\",\"relative\"),h.append(w),h.find(\".\"+c).children(\"input\").val(t.value),\"vertical\"===t.type?w.css({left:0,top:-48}):e.elemTemp.css(\"margin-right\",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find(\".\"+u).addClass(l)):e.slide(),e.elemTemp.find(\".\"+u).on(\"mouseover\",function(){var a=\"vertical\"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find(\".\"+o),l=\"vertical\"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data(\"value\"),u=t.setTips?t.setTips(r):r;e.elemTemp.find(\".\"+d).html(u),\"vertical\"===t.type?e.elemTemp.find(\".\"+d).css({bottom:s+\"%\",\"margin-bottom\":\"20px\",display:\"inline-block\"}):e.elemTemp.find(\".\"+d).css({left:s+\"%\",display:\"inline-block\"})}).on(\"mouseout\",function(){e.elemTemp.find(\".\"+d).css(\"display\",\"none\")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return\"vertical\"===l.type?l.height:s[0].offsetWidth},h=s.find(\".\"+o),y=s.next(\".\"+v),g=y.children(\".\"+c).children(\"input\").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css(\"vertical\"===l.type?\"bottom\":\"left\",e+\"%\");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;\"vertical\"===l.type?(s.find(\".\"+d).css({bottom:e+\"%\",\"margin-bottom\":\"20px\"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find(\".\"+d).css(\"left\",e+\"%\"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);\"vertical\"===l.type?s.find(\".\"+r).css({height:o+\"%\",bottom:n+\"%\"}):s.find(\".\"+r).css({width:o+\"%\",left:n+\"%\"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children(\".\"+c).children(\"input\").val(g),h.eq(i).data(\"value\",u),u=l.setTips?l.setTips(u):u,s.find(\".\"+d).html(u),l.range){var v=[h.eq(0).data(\"value\"),h.eq(1).data(\"value\")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['<div class=\"layui-auxiliar-moving\" id=\"LAY-slider-moving\"></div'].join(\"\")),M=function(e,t){var a=function(){t&&t(),w.remove()};i(\"#LAY-slider-moving\")[0]||i(\"body\").append(w),w.on(\"mousemove\",e),w.on(\"mouseup\",a).on(\"mouseleave\",a)};if(\"set\"===e)return x(t,a);s.find(\".\"+u).each(function(e){var t=i(this);t.on(\"mousedown\",function(i){i=i||window.event;var a=t.parent()[0].offsetLeft,n=i.clientX;\"vertical\"===l.type&&(a=f()-t.parent()[0].offsetTop-h.height(),n=i.clientY);var r=function(i){i=i||window.event;var r=a+(\"vertical\"===l.type?n-i.clientY:i.clientX-n);r<0&&(r=0),r>f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find(\".\"+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find(\".\"+d).hide()};M(r,o)})}),s.on(\"click\",function(e){var t=i(\".\"+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n=\"vertical\"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?\"vertical\"===l.type?Math.abs(n-parseInt(i(h[0]).css(\"bottom\")))>Math.abs(n-parseInt(i(h[1]).css(\"bottom\")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children(\".\"+m).fadeIn(\"fast\")},function(){var e=i(this);e.children(\".\"+m).fadeOut(\"fast\")}),y.children(\".\"+m).children(\"i\").each(function(e){i(this).on(\"click\",function(){g=1==e?g-l.step<l.min?l.min:Number(g)-l.step:Number(g)+l.step>l.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=e<l.min?l.min:e,e=e>l.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children(\".\"+c).children(\"input\").on(\"keydown\",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on(\"change\",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/table.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define([\"laytpl\",\"laypage\",\"layer\",\"form\",\"util\"],function(e){\"use strict\";var t=layui.$,i=layui.laytpl,a=layui.laypage,l=layui.layer,n=layui.form,o=(layui.util,layui.hint()),r=layui.device(),d={config:{checkName:\"LAY_CHECKED\",indexName:\"LAY_TABLE_INDEX\"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,y,e,t)}},c=function(){var e=this,t=e.config,i=t.id||t.index;return i&&(c.that[i]=e,c.config[i]=t),{config:t,reload:function(t){e.reload.call(e,t)},setColsWidth:function(){e.setColsWidth.call(e)},resize:function(){e.resize.call(e)}}},s=function(e){var t=c.config[e];return t||o.error(\"The ID option was not found in the table instance\"),t||null},u=function(e,a,l,n){var o=e.templet?function(){return\"function\"==typeof e.templet?e.templet(l):i(t(e.templet).html()||String(a)).render(l)}():a;return n?t(\"<div>\"+o+\"</div>\").text():o},y=\"table\",h=\".layui-table\",f=\"layui-hide\",p=\"layui-none\",v=\"layui-table-view\",m=\".layui-table-tool\",g=\".layui-table-box\",b=\".layui-table-init\",x=\".layui-table-header\",k=\".layui-table-body\",C=\".layui-table-main\",w=\".layui-table-fixed\",T=\".layui-table-fixed-l\",A=\".layui-table-fixed-r\",L=\".layui-table-total\",N=\".layui-table-page\",S=\".layui-table-sort\",W=\"layui-table-edit\",_=\"layui-table-hover\",E=function(e){var t='{{#if(item2.colspan){}} colspan=\"{{item2.colspan}}\"{{#} if(item2.rowspan){}} rowspan=\"{{item2.rowspan}}\"{{#}}}';return e=e||{},['<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>',\"<thead>\",\"{{# layui.each(d.data.cols, function(i1, item1){ }}\",\"<tr>\",\"{{# layui.each(item1, function(i2, item2){ }}\",'{{# if(item2.fixed && item2.fixed !== \"right\"){ left = true; } }}','{{# if(item2.fixed === \"right\"){ right = true; } }}',function(){return e.fixed&&\"right\"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== \"right\"){ }}':\"right\"===e.fixed?'{{# if(item2.fixed === \"right\"){ }}':\"\"}(),\"{{# var isSort = !(item2.colGroup) && item2.sort; }}\",'<th data-field=\"{{ item2.field||i2 }}\" data-key=\"{{d.index}}-{{i1}}-{{i2}}\" {{# if( item2.parentKey){ }}data-parentkey=\"{{ item2.parentKey }}\"{{# } }} {{# if(item2.minWidth){ }}data-minwidth=\"{{item2.minWidth}}\"{{# } }} '+t+' {{# if(item2.unresize || item2.colGroup){ }}data-unresize=\"true\"{{# } }} class=\"{{# if(item2.hide){ }}layui-hide{{# } }}{{# if(isSort){ }} layui-unselect{{# } }}{{# if(!item2.field){ }} layui-table-col-special{{# } }}\">','<div class=\"layui-table-cell laytable-cell-',\"{{# if(item2.colGroup){ }}\",\"group\",\"{{# } else { }}\",\"{{d.index}}-{{i1}}-{{i2}}\",'{{# if(item2.type !== \"normal\"){ }}',\" laytable-cell-{{ item2.type }}\",\"{{# } }}\",\"{{# } }}\",'\" {{#if(item2.align){}}align=\"{{item2.align}}\"{{#}}}>','{{# if(item2.type === \"checkbox\"){ }}','<input type=\"checkbox\" name=\"layTableCheckbox\" lay-skin=\"primary\" lay-filter=\"layTableAllChoose\" {{# if(item2[d.data.checkName]){ }}checked{{# }; }}>',\"{{# } else { }}\",'<span>{{item2.title||\"\"}}</span>',\"{{# if(isSort){ }}\",'<span class=\"layui-table-sort layui-inline\"><i class=\"layui-edge layui-table-sort-asc\" title=\"升序\"></i><i class=\"layui-edge layui-table-sort-desc\" title=\"降序\"></i></span>',\"{{# } }}\",\"{{# } }}\",\"</div>\",\"</th>\",e.fixed?\"{{# }; }}\":\"\",\"{{# }); }}\",\"</tr>\",\"{{# }); }}\",\"</thead>\",\"</table>\"].join(\"\")},z=['<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>',\"<tbody></tbody>\",\"</table>\"].join(\"\"),H=['<div class=\"layui-form layui-border-box {{d.VIEW_CLASS}}\" lay-filter=\"LAY-table-{{d.index}}\" lay-id=\"{{ d.data.id }}\" style=\"{{# if(d.data.width){ }}width:{{d.data.width}}px;{{# } }} {{# if(d.data.height){ }}height:{{d.data.height}}px;{{# } }}\">',\"{{# if(d.data.toolbar){ }}\",'<div class=\"layui-table-tool\">','<div class=\"layui-table-tool-temp\"></div>','<div class=\"layui-table-tool-self\"></div>',\"</div>\",\"{{# } }}\",'<div class=\"layui-table-box\">',\"{{# if(d.data.loading){ }}\",'<div class=\"layui-table-init\" style=\"background-color: #fff;\">','<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop\"></i>',\"</div>\",\"{{# } }}\",\"{{# var left, right; }}\",'<div class=\"layui-table-header\">',E(),\"</div>\",'<div class=\"layui-table-body layui-table-main\">',z,\"</div>\",\"{{# if(left){ }}\",'<div class=\"layui-table-fixed layui-table-fixed-l\">','<div class=\"layui-table-header\">',E({fixed:!0}),\"</div>\",'<div class=\"layui-table-body\">',z,\"</div>\",\"</div>\",\"{{# }; }}\",\"{{# if(right){ }}\",'<div class=\"layui-table-fixed layui-table-fixed-r\">','<div class=\"layui-table-header\">',E({fixed:\"right\"}),'<div class=\"layui-table-mend\"></div>',\"</div>\",'<div class=\"layui-table-body\">',z,\"</div>\",\"</div>\",\"{{# }; }}\",\"</div>\",\"{{# if(d.data.totalRow){ }}\",'<div class=\"layui-table-total\">','<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>','<tbody><tr><td><div class=\"layui-table-cell\" style=\"visibility: hidden;\">Total</div></td></tr></tbody>',\"</table>\",\"</div>\",\"{{# } }}\",\"{{# if(d.data.page){ }}\",'<div class=\"layui-table-page\">','<div id=\"layui-table-page{{d.index}}\"></div>',\"</div>\",\"{{# } }}\",\"<style>\",\"{{# layui.each(d.data.cols, function(i1, item1){\",\"layui.each(item1, function(i2, item2){ }}\",\".laytable-cell-{{d.index}}-{{i1}}-{{i2}}{ \",\"{{# if(item2.width){ }}\",\"width: {{item2.width}}px;\",\"{{# } }}\",\" }\",\"{{# });\",\"}); }}\",\"</style>\",\"</div>\"].join(\"\"),R=t(window),F=t(document),I=function(e){var i=this;i.index=++d.index,i.config=t.extend({},i.config,d.config,e),i.render()};I.prototype.config={limit:10,loading:!0,cellMinWidth:60,defaultToolbar:[\"filter\",\"exports\",\"print\"],autoSort:!0,text:{none:\"无数据\"}},I.prototype.render=function(){var e=this,a=e.config;if(a.elem=t(a.elem),a.where=a.where||{},a.id=a.id||a.elem.attr(\"id\")||e.index,a.request=t.extend({pageName:\"page\",limitName:\"limit\"},a.request),a.response=t.extend({statusName:\"code\",statusCode:0,msgName:\"msg\",dataName:\"data\",countName:\"count\"},a.response),\"object\"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,e.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return e;a.height&&/^full-\\d+$/.test(a.height)&&(e.fullHeightGap=a.height.split(\"-\")[1],a.height=R.height()-e.fullHeightGap),e.setInit();var l=a.elem,n=l.next(\".\"+v),o=e.elem=t(i(H).render({VIEW_CLASS:v,data:a,index:e.index}));if(a.index=e.index,e.key=a.id||a.index,n[0]&&n.remove(),l.after(o),e.layTool=o.find(m),e.layBox=o.find(g),e.layHeader=o.find(x),e.layMain=o.find(C),e.layBody=o.find(k),e.layFixed=o.find(w),e.layFixLeft=o.find(T),e.layFixRight=o.find(A),e.layTotal=o.find(L),e.layPage=o.find(N),e.renderToolbar(),e.fullSize(),a.cols.length>1){var r=e.layFixed.find(x).find(\"th\");r.height(e.layHeader.height()-1-parseFloat(r.css(\"padding-top\"))-parseFloat(r.css(\"padding-bottom\")))}e.pullData(e.page),e.events()},I.prototype.initOpts=function(e){var t=this,i=(t.config,{checkbox:48,radio:48,space:15,numbers:40});e.checkbox&&(e.type=\"checkbox\"),e.space&&(e.type=\"space\"),e.type||(e.type=\"normal\"),\"normal\"!==e.type&&(e.unresize=!0,e.width=e.width||i[e.type])},I.prototype.setInit=function(e){var t=this,i=t.config;return i.clientWidth=i.width||function(){var e=function(t){var a,l;t=t||i.elem.parent(),a=t.width();try{l=\"none\"===t.css(\"display\")}catch(n){}return!t[0]||a&&!l?a:e(t.parent())};return e()}(),\"width\"===e?i.clientWidth:void layui.each(i.cols,function(e,a){layui.each(a,function(l,n){if(!n)return void a.splice(l,1);if(n.key=e+\"-\"+l,n.hide=n.hide||!1,n.colGroup||n.colspan>1){var o=0;layui.each(i.cols[e+1],function(t,i){i.HAS_PARENT||o>1&&o==n.colspan||(i.HAS_PARENT=!0,i.parentKey=e+\"-\"+l,o+=parseInt(i.colspan>1?i.colspan:1))}),n.colGroup=!0}t.initOpts(n)})})},I.prototype.renderToolbar=function(){var e=this,a=e.config,l=['<div class=\"layui-inline\" lay-event=\"add\"><i class=\"layui-icon layui-icon-add-1\"></i></div>','<div class=\"layui-inline\" lay-event=\"update\"><i class=\"layui-icon layui-icon-edit\"></i></div>','<div class=\"layui-inline\" lay-event=\"delete\"><i class=\"layui-icon layui-icon-delete\"></i></div>'].join(\"\"),n=e.layTool.find(\".layui-table-tool-temp\");if(\"default\"===a.toolbar)n.html(l);else if(\"string\"==typeof a.toolbar){var o=t(a.toolbar).html()||\"\";o&&n.html(i(o).render(a))}var r={filter:{title:\"筛选列\",layEvent:\"LAYTABLE_COLS\",icon:\"layui-icon-cols\"},exports:{title:\"导出\",layEvent:\"LAYTABLE_EXPORT\",icon:\"layui-icon-export\"},print:{title:\"打印\",layEvent:\"LAYTABLE_PRINT\",icon:\"layui-icon-print\"}},d=[];\"object\"==typeof a.defaultToolbar&&layui.each(a.defaultToolbar,function(e,t){var i=r[t];i&&d.push('<div class=\"layui-inline\" title=\"'+i.title+'\" lay-event=\"'+i.layEvent+'\"><i class=\"layui-icon '+i.icon+'\"></i></div>')}),e.layTool.find(\".layui-table-tool-self\").html(d.join(\"\"))},I.prototype.setParentCol=function(e,t){var i=this,a=i.config,l=i.layHeader.find('th[data-key=\"'+a.index+\"-\"+t+'\"]'),n=parseInt(l.attr(\"colspan\"))||0;if(l[0]){var o=t.split(\"-\"),r=a.cols[o[0]][o[1]];e?n--:n++,l.attr(\"colspan\",n),l[n<1?\"addClass\":\"removeClass\"](f),r.colspan=n,r.hide=n<1;var d=l.data(\"parentkey\");d&&i.setParentCol(e,d)}},I.prototype.setColsPatch=function(){var e=this,t=e.config;layui.each(t.cols,function(t,i){layui.each(i,function(t,i){i.hide&&e.setParentCol(i.hide,i.parentKey)})})},I.prototype.setColsWidth=function(){var e=this,t=e.config,i=0,a=0,l=0,n=0,o=e.setInit(\"width\");e.eachCols(function(e,t){t.hide||i++}),o=o-function(){return\"line\"===t.skin||\"nob\"===t.skin?2:i+1}()-e.getScrollWidth(e.layMain[0])-1;var r=function(e){layui.each(t.cols,function(i,r){layui.each(r,function(i,d){var c=0,s=d.minWidth||t.cellMinWidth;return d?void(d.colGroup||d.hide||(e?l&&l<s&&(a--,c=s):(c=d.width||0,/\\d+%$/.test(c)?(c=Math.floor(parseFloat(c)/100*o),c<s&&(c=s)):c||(d.width=c=0,a++)),d.hide&&(c=0),n+=c)):void r.splice(i,1)})}),o>n&&a&&(l=(o-n)/a)};r(),r(!0),e.autoColNums=a,e.eachCols(function(i,a){var n=a.minWidth||t.cellMinWidth;a.colGroup||a.hide||(0===a.width?e.getCssRule(t.index+\"-\"+a.key,function(e){e.style.width=Math.floor(l>=n?l:n)+\"px\"}):/\\d+%$/.test(a.width)&&e.getCssRule(t.index+\"-\"+a.key,function(e){e.style.width=Math.floor(parseFloat(a.width)/100*o)+\"px\"}))});var d=e.layMain.width()-e.getScrollWidth(e.layMain[0])-e.layMain.children(\"table\").outerWidth();if(e.autoColNums&&d>=-i&&d<=i){var c=function(t){var i;return t=t||e.layHeader.eq(0).find(\"thead th:last-child\"),i=t.data(\"field\"),!i&&t.prev()[0]?c(t.prev()):t},s=c(),u=s.data(\"key\");e.getCssRule(u,function(t){var i=t.style.width||s.outerWidth();t.style.width=parseFloat(i)+d+\"px\",e.layMain.height()-e.layMain.prop(\"clientHeight\")>0&&(t.style.width=parseFloat(t.style.width)-1+\"px\")})}e.loading(!0)},I.prototype.resize=function(){var e=this;e.fullSize(),e.setColsWidth(),e.scrollPatch()},I.prototype.reload=function(e){var i=this;e=e||{},delete i.haveInit,e.data&&e.data.constructor===Array&&delete i.config.data,i.config=t.extend(!0,{},i.config,e),i.render()},I.prototype.errorView=function(e){var i=this,a=i.layMain.find(\".\"+p),l=t('<div class=\"'+p+'\">'+(e||\"Error\")+\"</div>\");a[0]&&(i.layNone.remove(),a.remove()),i.layFixed.addClass(f),i.layMain.find(\"tbody\").html(\"\"),i.layMain.append(i.layNone=l),d.cache[i.key]=[]},I.prototype.page=1,I.prototype.pullData=function(e){var i=this,a=i.config,l=a.request,n=a.response,o=function(){\"object\"==typeof a.initSort&&i.sort(a.initSort.field,a.initSort.type)};if(i.startTime=(new Date).getTime(),a.url){var r={};r[l.pageName]=e,r[l.limitName]=a.limit;var d=t.extend(r,a.where);a.contentType&&0==a.contentType.indexOf(\"application/json\")&&(d=JSON.stringify(d)),i.loading(),t.ajax({type:a.method||\"get\",url:a.url,contentType:a.contentType,data:d,dataType:\"json\",headers:a.headers||{},success:function(t){\"function\"==typeof a.parseData&&(t=a.parseData(t)||t),t[n.statusName]!=n.statusCode?(i.renderForm(),i.errorView(t[n.msgName]||'返回的数据不符合规范，正确的成功状态码应为：\"'+n.statusName+'\": '+n.statusCode)):(i.renderData(t,e,t[n.countName]),o(),a.time=(new Date).getTime()-i.startTime+\" ms\"),i.setColsWidth(),\"function\"==typeof a.done&&a.done(t,e,t[n.countName])},error:function(e,t){i.errorView(\"数据接口请求异常：\"+t),i.renderForm(),i.setColsWidth()}})}else if(a.data&&a.data.constructor===Array){var c={},s=e*a.limit-a.limit;c[n.dataName]=a.data.concat().splice(s,a.limit),c[n.countName]=a.data.length,i.renderData(c,e,c[n.countName]),o(),i.setColsWidth(),\"function\"==typeof a.done&&a.done(c,e,c[n.countName])}},I.prototype.eachCols=function(e){var t=this;return d.eachCols(null,e,t.config.cols),t},I.prototype.renderData=function(e,n,o,r){var c=this,s=c.config,y=e[s.response.dataName]||[],h=[],v=[],m=[],g=function(){var e;return!r&&c.sortKey?c.sort(c.sortKey.field,c.sortKey.sort,!0):(layui.each(y,function(a,l){var o=[],y=[],p=[],g=a+s.limit*(n-1)+1;0!==l.length&&(r||(l[d.config.indexName]=a),c.eachCols(function(n,r){var c=r.field||n,h=s.index+\"-\"+r.key,v=l[c];if(void 0!==v&&null!==v||(v=\"\"),!r.colGroup){var m=['<td data-field=\"'+c+'\" data-key=\"'+h+'\" '+function(){var e=[];return r.edit&&e.push('data-edit=\"'+r.edit+'\"'),r.align&&e.push('align=\"'+r.align+'\"'),r.templet&&e.push('data-content=\"'+v+'\"'),r.toolbar&&e.push('data-off=\"true\"'),r.event&&e.push('lay-event=\"'+r.event+'\"'),r.style&&e.push('style=\"'+r.style+'\"'),r.minWidth&&e.push('data-minwidth=\"'+r.minWidth+'\"'),e.join(\" \")}()+' class=\"'+function(){var e=[];return r.hide&&e.push(f),r.field||e.push(\"layui-table-col-special\"),e.join(\" \")}()+'\">','<div class=\"layui-table-cell laytable-cell-'+function(){return\"normal\"===r.type?h:h+\" laytable-cell-\"+r.type}()+'\">'+function(){var n=t.extend(!0,{LAY_INDEX:g},l),o=d.config.checkName;switch(r.type){case\"checkbox\":return'<input type=\"checkbox\" name=\"layTableCheckbox\" lay-skin=\"primary\" '+function(){return r[o]?(l[o]=r[o],r[o]?\"checked\":\"\"):n[o]?\"checked\":\"\"}()+\">\";case\"radio\":return n[o]&&(e=a),'<input type=\"radio\" name=\"layTableRadio_'+s.index+'\" '+(n[o]?\"checked\":\"\")+' lay-type=\"layTableRadio\">';case\"numbers\":return g}return r.toolbar?i(t(r.toolbar).html()||\"\").render(n):u(r,v,n)}(),\"</div></td>\"].join(\"\");o.push(m),r.fixed&&\"right\"!==r.fixed&&y.push(m),\"right\"===r.fixed&&p.push(m)}}),h.push('<tr data-index=\"'+a+'\">'+o.join(\"\")+\"</tr>\"),v.push('<tr data-index=\"'+a+'\">'+y.join(\"\")+\"</tr>\"),m.push('<tr data-index=\"'+a+'\">'+p.join(\"\")+\"</tr>\"))}),c.layBody.scrollTop(0),c.layMain.find(\".\"+p).remove(),c.layMain.find(\"tbody\").html(h.join(\"\")),c.layFixLeft.find(\"tbody\").html(v.join(\"\")),c.layFixRight.find(\"tbody\").html(m.join(\"\")),c.renderForm(),\"number\"==typeof e&&c.setThisRowChecked(e),c.syncCheckAll(),c.haveInit?c.scrollPatch():setTimeout(function(){c.scrollPatch()},50),c.haveInit=!0,l.close(c.tipsIndex),s.HAS_SET_COLS_PATCH||c.setColsPatch(),void(s.HAS_SET_COLS_PATCH=!0))};return d.cache[c.key]=y,c.layPage[0==o||0===y.length&&1==n?\"addClass\":\"removeClass\"](f),r?g():0===y.length?(c.renderForm(),c.errorView(s.text.none)):(c.layFixed.removeClass(f),g(),c.renderTotal(y),void(s.page&&(s.page=t.extend({elem:\"layui-table-page\"+s.index,count:o,limit:s.limit,limits:s.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:[\"prev\",\"page\",\"next\",\"skip\",\"count\",\"limit\"],prev:'<i class=\"layui-icon\">&#xe603;</i>',next:'<i class=\"layui-icon\">&#xe602;</i>',jump:function(e,t){t||(c.page=e.curr,s.limit=e.limit,c.pullData(e.curr))}},s.page),s.page.count=o,a.render(s.page))))},I.prototype.renderTotal=function(e){var t=this,i=t.config,a={};if(i.totalRow){layui.each(e,function(e,i){0!==i.length&&t.eachCols(function(e,t){var l=t.field||e,n=i[l];t.totalRow&&(a[l]=(a[l]||0)+(parseFloat(n)||0))})});var l=[];t.eachCols(function(e,t){var n=t.field||e,o=['<td data-field=\"'+n+'\" data-key=\"'+i.index+\"-\"+t.key+'\" '+function(){var e=[];return t.align&&e.push('align=\"'+t.align+'\"'),t.style&&e.push('style=\"'+t.style+'\"'),t.minWidth&&e.push('data-minwidth=\"'+t.minWidth+'\"'),e.join(\" \")}()+' class=\"'+function(){var e=[];return t.hide&&e.push(f),t.field||e.push(\"layui-table-col-special\"),e.join(\" \")}()+'\">','<div class=\"layui-table-cell laytable-cell-'+function(){var e=i.index+\"-\"+t.key;return\"normal\"===t.type?e:e+\" laytable-cell-\"+t.type}()+'\">'+function(){var e=t.totalRowText||\"\";return t.totalRow?parseFloat(a[n]).toFixed(2)||e:e}(),\"</div></td>\"].join(\"\");l.push(o)}),t.layTotal.find(\"tbody\").html(\"<tr>\"+l.join(\"\")+\"</tr>\")}},I.prototype.getColElem=function(e,t){var i=this,a=i.config;return e.eq(0).find(\".laytable-cell-\"+(a.index+\"-\"+t)+\":eq(0)\")},I.prototype.renderForm=function(e){n.render(e,\"LAY-table-\"+this.index)},I.prototype.setThisRowChecked=function(e){var t=this,i=(t.config,\"layui-table-click\"),a=t.layBody.find('tr[data-index=\"'+e+'\"]');a.addClass(i).siblings(\"tr\").removeClass(i)},I.prototype.sort=function(e,i,a,l){var n,r,c=this,s={},u=c.config,h=u.elem.attr(\"lay-filter\"),f=d.cache[c.key];\"string\"==typeof e&&c.layHeader.find(\"th\").each(function(i,a){var l=t(this),o=l.data(\"field\");if(o===e)return e=l,n=o,!1});try{var n=n||e.data(\"field\"),p=e.data(\"key\");if(c.sortKey&&!a&&n===c.sortKey.field&&i===c.sortKey.sort)return;var v=c.layHeader.find(\"th .laytable-cell-\"+p).find(S);c.layHeader.find(\"th\").find(S).removeAttr(\"lay-sort\"),v.attr(\"lay-sort\",i||null),c.layFixed.find(\"th\")}catch(m){return o.error(\"Table modules: Did not match to field\")}c.sortKey={field:n,sort:i},u.autoSort&&(\"asc\"===i?r=layui.sort(f,n):\"desc\"===i?r=layui.sort(f,n,!0):(r=layui.sort(f,d.config.indexName),delete c.sortKey)),s[u.response.dataName]=r||f,c.renderData(s,c.page,c.count,!0),l&&layui.event.call(e,y,\"sort(\"+h+\")\",{field:n,type:i})},I.prototype.loading=function(e){var i=this,a=i.config;a.loading&&(e?(i.layInit&&i.layInit.remove(),delete i.layInit,i.layBox.find(b).remove()):(i.layInit=t(['<div class=\"layui-table-init\">','<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop\"></i>',\"</div>\"].join(\"\")),i.layBox.append(i.layInit)))},I.prototype.setCheckData=function(e,t){var i=this,a=i.config,l=d.cache[i.key];l[e]&&l[e].constructor!==Array&&(l[e][a.checkName]=t)},I.prototype.syncCheckAll=function(){var e=this,t=e.config,i=e.layHeader.find('input[name=\"layTableCheckbox\"]'),a=function(i){return e.eachCols(function(e,a){\"checkbox\"===a.type&&(a[t.checkName]=i)}),i};i[0]&&(d.checkStatus(e.key).isAll?(i[0].checked||(i.prop(\"checked\",!0),e.renderForm(\"checkbox\")),a(!0)):(i[0].checked&&(i.prop(\"checked\",!1),e.renderForm(\"checkbox\")),a(!1)))},I.prototype.getCssRule=function(e,t){var i=this,a=i.elem.find(\"style\")[0],l=a.sheet||a.styleSheet||{},n=l.cssRules||l.rules;layui.each(n,function(i,a){if(a.selectorText===\".laytable-cell-\"+e)return t(a),!0})},I.prototype.fullSize=function(){var e,t=this,i=t.config,a=i.height;t.fullHeightGap&&(a=R.height()-t.fullHeightGap,a<135&&(a=135),t.elem.css(\"height\",a)),a&&(e=parseFloat(a)-(t.layHeader.outerHeight()||38),i.toolbar&&(e-=t.layTool.outerHeight()||50),i.totalRow&&(e-=t.layTotal.outerHeight()||40),i.page&&(e-=t.layPage.outerHeight()||41),t.layMain.css(\"height\",e-2))},I.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:(e=document.createElement(\"div\"),e.style.width=\"100px\",e.style.height=\"100px\",e.style.overflowY=\"scroll\",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},I.prototype.scrollPatch=function(){var e=this,i=e.layMain.children(\"table\"),a=e.layMain.width()-e.layMain.prop(\"clientWidth\"),l=e.layMain.height()-e.layMain.prop(\"clientHeight\"),n=(e.getScrollWidth(e.layMain[0]),i.outerWidth()-e.layMain.width()),o=function(e){if(a&&l){if(e=e.eq(0),!e.find(\".layui-table-patch\")[0]){var i=t('<th class=\"layui-table-patch\"><div class=\"layui-table-cell\"></div></th>');i.find(\"div\").css({width:a}),e.find(\"tr\").append(i)}}else e.find(\".layui-table-patch\").remove()};o(e.layHeader),o(e.layTotal);var r=e.layMain.height(),d=r-l;e.layFixed.find(k).css(\"height\",i.height()>=d?d:\"auto\"),e.layFixRight[n>0?\"removeClass\":\"addClass\"](f),e.layFixRight.css(\"right\",a-1)},I.prototype.events=function(){var e,a=this,o=a.config,c=t(\"body\"),s={},u=a.layHeader.find(\"th\"),h=\".layui-table-cell\",p=o.elem.attr(\"lay-filter\");a.layTool.on(\"click\",\"*[lay-event]\",function(e){var i=t(this),c=i.attr(\"lay-event\"),s=function(e){var l=t(e.list),n=t('<ul class=\"layui-table-tool-panel\"></ul>');n.html(l),o.height&&n.css(\"max-height\",o.height-(a.layTool.outerHeight()||50)),i.find(\".layui-table-tool-panel\")[0]||i.append(n),a.renderForm(),n.on(\"click\",function(e){layui.stope(e)}),e.done&&e.done(n,l)};switch(layui.stope(e),F.trigger(\"table.tool.panel.remove\"),l.close(a.tipsIndex),c){case\"LAYTABLE_COLS\":s({list:function(){var e=[];return a.eachCols(function(t,i){i.field&&\"normal\"==i.type&&e.push('<li><input type=\"checkbox\" name=\"'+i.field+'\" data-key=\"'+i.key+'\" data-parentkey=\"'+(i.parentKey||\"\")+'\" lay-skin=\"primary\" '+(i.hide?\"\":\"checked\")+' title=\"'+(i.title||i.field)+'\" lay-filter=\"LAY_TABLE_TOOL_COLS\"></li>')}),e.join(\"\")}(),done:function(){n.on(\"checkbox(LAY_TABLE_TOOL_COLS)\",function(e){var i=t(e.elem),l=this.checked,n=i.data(\"key\"),r=i.data(\"parentkey\");layui.each(o.cols,function(e,t){layui.each(t,function(t,i){if(e+\"-\"+t===n){var d=i.hide;i.hide=!l,a.elem.find('*[data-key=\"'+o.index+\"-\"+n+'\"]')[l?\"removeClass\":\"addClass\"](f),d!=i.hide&&a.setParentCol(!l,r),a.resize()}})})})}});break;case\"LAYTABLE_EXPORT\":r.ie?l.tips(\"导出功能不支持 IE，请用 Chrome 等高级浏览器导出\",this,{tips:3}):s({list:function(){return['<li data-type=\"csv\">导出到 Csv 文件</li>','<li data-type=\"xls\">导出到 Excel 文件</li>'].join(\"\")}(),done:function(e,i){i.on(\"click\",function(){var e=t(this).data(\"type\");d.exportFile(o.id,null,e)})}});break;case\"LAYTABLE_PRINT\":var u=window.open(\"打印窗口\",\"_blank\"),h=[\"<style>\",\"body{font-size: 12px; color: #666;}\",\"table{width: 100%; border-collapse: collapse; border-spacing: 0;}\",\"th,td{line-height: 20px; padding: 9px 15px; border: 1px solid #ccc; text-align: left; font-size: 12px; color: #666;}\",\"a{color: #666; text-decoration:none;}\",\"*.layui-hide{display: none}\",\"</style>\"].join(\"\"),v=t(a.layHeader.html());v.append(a.layMain.find(\"table\").html()),v.append(a.layTotal.find(\"table\").html()),v.find(\"th.layui-table-patch\").remove(),v.find(\".layui-table-col-special\").remove(),u.document.write(h+v.prop(\"outerHTML\")),u.document.close(),u.print(),u.close()}layui.event.call(this,y,\"toolbar(\"+p+\")\",t.extend({event:c,config:o},{}))}),u.on(\"mousemove\",function(e){var i=t(this),a=i.offset().left,l=e.clientX-a;i.data(\"unresize\")||s.resizeStart||(s.allowResize=i.width()-l<=10,c.css(\"cursor\",s.allowResize?\"col-resize\":\"\"))}).on(\"mouseleave\",function(){t(this);s.resizeStart||c.css(\"cursor\",\"\")}).on(\"mousedown\",function(e){var i=t(this);if(s.allowResize){var l=i.data(\"key\");e.preventDefault(),s.resizeStart=!0,s.offset=[e.clientX,e.clientY],a.getCssRule(l,function(e){var t=e.style.width||i.outerWidth();s.rule=e,s.ruleWidth=parseFloat(t),s.minWidth=i.data(\"minwidth\")||o.cellMinWidth})}}),F.on(\"mousemove\",function(t){if(s.resizeStart){if(t.preventDefault(),s.rule){var i=s.ruleWidth+t.clientX-s.offset[0];i<s.minWidth&&(i=s.minWidth),s.rule.style.width=i+\"px\",l.close(a.tipsIndex)}e=1}}).on(\"mouseup\",function(t){s.resizeStart&&(s={},c.css(\"cursor\",\"\"),a.scrollPatch()),2===e&&(e=null)}),u.on(\"click\",function(i){var l,n=t(this),o=n.find(S),r=o.attr(\"lay-sort\");return o[0]&&1!==e?(l=\"asc\"===r?\"desc\":\"desc\"===r?null:\"asc\",void a.sort(n,l,null,!0)):e=2}).find(S+\" .layui-edge \").on(\"click\",function(e){var i=t(this),l=i.index(),n=i.parents(\"th\").eq(0).data(\"field\");layui.stope(e),0===l?a.sort(n,\"asc\",null,!0):a.sort(n,\"desc\",null,!0)});var v=function(e){var l=t(this),n=l.parents(\"tr\").eq(0).data(\"index\"),o=a.layBody.find('tr[data-index=\"'+n+'\"]'),r=d.cache[a.key]||[];return r=r[n]||{},t.extend({tr:o,data:d.clearCacheKey(r),del:function(){d.cache[a.key][n]=[],o.remove(),a.scrollPatch()},update:function(e){e=e||{},layui.each(e,function(e,l){if(e in r){var n,d=o.children('td[data-field=\"'+e+'\"]');r[e]=l,a.eachCols(function(t,i){i.field==e&&i.templet&&(n=i.templet)}),d.children(h).html(function(){return n?function(){return\"function\"==typeof n?n(r):i(t(n).html()||l).render(r)}():l}()),d.data(\"content\",l)}})}},e)};a.elem.on(\"click\",'input[name=\"layTableCheckbox\"]+',function(){var e=t(this).prev(),i=a.layBody.find('input[name=\"layTableCheckbox\"]'),l=e.parents(\"tr\").eq(0).data(\"index\"),n=e[0].checked,o=\"layTableAllChoose\"===e.attr(\"lay-filter\");o?(i.each(function(e,t){t.checked=n,a.setCheckData(e,n)}),a.syncCheckAll(),a.renderForm(\"checkbox\")):(a.setCheckData(l,n),a.syncCheckAll()),layui.event.call(e[0],y,\"checkbox(\"+p+\")\",v.call(e[0],{checked:n,type:o?\"all\":\"one\"}))}),a.elem.on(\"click\",'input[lay-type=\"layTableRadio\"]+',function(){var e=t(this).prev(),i=e[0].checked,l=d.cache[a.key],n=e.parents(\"tr\").eq(0).data(\"index\");layui.each(l,function(e,t){n===e?t.LAY_CHECKED=!0:delete t.LAY_CHECKED}),a.setThisRowChecked(n),layui.event.call(this,y,\"radio(\"+p+\")\",v.call(this,{checked:i}))}),a.layBody.on(\"mouseenter\",\"tr\",function(){var e=t(this),i=e.index();e.data(\"off\")||a.layBody.find(\"tr:eq(\"+i+\")\").addClass(_)}).on(\"mouseleave\",\"tr\",function(){var e=t(this),i=e.index();e.data(\"off\")||a.layBody.find(\"tr:eq(\"+i+\")\").removeClass(_)}).on(\"click\",\"tr\",function(){m.call(this,\"row\")}).on(\"dblclick\",\"tr\",function(){m.call(this,\"rowDouble\")});var m=function(e){var i=t(this);i.data(\"off\")||layui.event.call(this,y,e+\"(\"+p+\")\",v.call(i.children(\"td\")[0]))};a.layBody.on(\"change\",\".\"+W,function(){var e=t(this),i=this.value,l=e.parent().data(\"field\"),n=e.parents(\"tr\").eq(0).data(\"index\"),o=d.cache[a.key][n];o[l]=i,layui.event.call(this,y,\"edit(\"+p+\")\",v.call(this,{value:i,field:l}))}).on(\"blur\",\".\"+W,function(){var e,l=t(this),n=this,o=l.parent().data(\"field\"),r=l.parents(\"tr\").eq(0).data(\"index\"),c=d.cache[a.key][r];a.eachCols(function(t,i){i.field==o&&i.templet&&(e=i.templet)}),l.siblings(h).html(function(a){return e?function(){return\"function\"==typeof e?e(c):i(t(e).html()||n.value).render(c)}():a}(n.value)),l.parent().data(\"content\",n.value),l.remove()}),a.layBody.on(\"click\",\"td\",function(e){var i=t(this),a=(i.data(\"field\"),i.data(\"edit\")),l=i.children(h);if(!i.data(\"off\")&&a){var n=t('<input class=\"layui-input '+W+'\">');return n[0].value=i.data(\"content\")||l.text(),i.find(\".\"+W)[0]||i.append(n),n.focus(),void layui.stope(e)}}).on(\"mouseenter\",\"td\",function(){b.call(this)}).on(\"mouseleave\",\"td\",function(){b.call(this,\"hide\")});var g=\"layui-table-grid-down\",b=function(e){var i=t(this),a=i.children(h);if(!i.data(\"off\"))if(e)i.find(\".layui-table-grid-down\").remove();else if(a.prop(\"scrollWidth\")>a.outerWidth()){if(a.find(\".\"+g)[0])return;i.append('<div class=\"'+g+'\"><i class=\"layui-icon layui-icon-down\"></i></div>')}};a.layBody.on(\"click\",\".\"+g,function(e){var i=t(this),n=i.parent(),d=n.children(h);a.tipsIndex=l.tips(['<div class=\"layui-table-tips-main\" style=\"margin-top: -'+(d.height()+16)+\"px;\"+function(){return\"sm\"===o.size?\"padding: 4px 15px; font-size: 12px;\":\"lg\"===o.size?\"padding: 14px 15px;\":\"\"}()+'\">',d.html(),\"</div>\",'<i class=\"layui-icon layui-table-tips-c layui-icon-close\"></i>'].join(\"\"),d[0],{tips:[3,\"\"],time:-1,anim:-1,maxWidth:r.ios||r.android?300:a.elem.width()/2,isOutAnim:!1,skin:\"layui-table-tips\",success:function(e,t){e.find(\".layui-table-tips-c\").on(\"click\",function(){l.close(t)})}}),layui.stope(e)}),a.layBody.on(\"click\",\"*[lay-event]\",function(){var e=t(this),i=e.parents(\"tr\").eq(0).data(\"index\");layui.event.call(this,y,\"tool(\"+p+\")\",v.call(this,{event:e.attr(\"lay-event\")})),a.setThisRowChecked(i)}),a.layMain.on(\"scroll\",function(){var e=t(this),i=e.scrollLeft(),n=e.scrollTop();a.layHeader.scrollLeft(i),a.layTotal.scrollLeft(i),a.layFixed.find(k).scrollTop(n),l.close(a.tipsIndex)}),F.on(\"click\",function(){F.trigger(\"table.remove.tool.panel\")}),F.on(\"table.remove.tool.panel\",function(){t(\".layui-table-tool-panel\").remove()}),R.on(\"resize\",function(){a.resize()})},d.init=function(e,i){i=i||{};var a=this,l=t(e?'table[lay-filter=\"'+e+'\"]':h+\"[lay-data]\"),n=\"Table element property lay-data configuration item has a syntax error: \";return l.each(function(){var a=t(this),l=a.attr(\"lay-data\");try{l=new Function(\"return \"+l)()}catch(r){o.error(n+l)}var c=[],s=t.extend({elem:this,cols:[],data:[],skin:a.attr(\"lay-skin\"),size:a.attr(\"lay-size\"),even:\"string\"==typeof a.attr(\"lay-even\")},d.config,i,l);e&&a.hide(),a.find(\"thead>tr\").each(function(e){s.cols[e]=[],t(this).children().each(function(i){var a=t(this),l=a.attr(\"lay-data\");try{l=new Function(\"return \"+l)()}catch(r){return o.error(n+l)}var d=t.extend({title:a.text(),colspan:a.attr(\"colspan\")||0,rowspan:a.attr(\"rowspan\")||0},l);d.colspan<2&&c.push(d),s.cols[e].push(d)})}),a.find(\"tbody>tr\").each(function(e){var i=t(this),a={};i.children(\"td\").each(function(e,i){var l=t(this),n=l.data(\"field\");if(n)return a[n]=l.html()}),layui.each(c,function(e,t){var l=i.children(\"td\").eq(e);a[t.field]=l.html()}),s.data[e]=a}),d.render(s)}),a},c.that={},c.config={},d.eachCols=function(e,i,a){var l=c.config[e]||{},n=[],o=0;a=t.extend(!0,[],a||l.cols),layui.each(a,function(e,t){layui.each(t,function(t,i){if(i.colGroup){var l=0;o++,i.CHILD_COLS=[],layui.each(a[e+1],function(e,t){t.PARENT_COL_INDEX||l>1&&l==i.colspan||(t.PARENT_COL_INDEX=o,i.CHILD_COLS.push(t),l+=parseInt(t.colspan>1?t.colspan:1))})}i.PARENT_COL_INDEX||n.push(i)})});var r=function(e){layui.each(e||n,function(e,t){return t.CHILD_COLS?r(t.CHILD_COLS):void(\"function\"==typeof i&&i(e,t))})};r()},d.checkStatus=function(e){var t=0,i=0,a=[],l=d.cache[e]||[];return layui.each(l,function(e,l){return l.constructor===Array?void i++:void(l[d.config.checkName]&&(t++,a.push(d.clearCacheKey(l))))}),{data:a,isAll:!!l.length&&t===l.length-i}},d.exportFile=function(e,t,i){t=t||d.clearCacheKey(d.cache[e]),i=i||\"csv\";var a=c.config[e]||{},l={csv:\"text/csv\",xls:\"application/vnd.ms-excel\"}[i],n=document.createElement(\"a\");return r.ie?o.error(\"IE_NOT_SUPPORT_EXPORTS\"):(n.href=\"data:\"+l+\";charset=utf-8,\\ufeff\"+encodeURIComponent(function(){var i=[],a=[];return layui.each(t,function(t,l){var n=[];\"object\"==typeof e?(layui.each(e,function(e,a){0==t&&i.push(a||\"\")}),layui.each(d.clearCacheKey(l),function(e,t){n.push('\"'+(t||\"\")+'\"')})):d.eachCols(e,function(e,a){a.field&&\"normal\"==a.type&&!a.hide&&(0==t&&i.push(a.title||\"\"),n.push('\"'+u(a,l[a.field],l,\"text\")+'\"'))}),a.push(n.join(\",\"))}),i.join(\",\")+\"\\r\\n\"+a.join(\"\\r\\n\")}()),n.download=(a.title||\"table_\"+(a.index||\"\"))+\".\"+i,document.body.appendChild(n),n.click(),void document.body.removeChild(n))},d.resize=function(e){if(e){var t=s(e);if(!t)return;c.that[e].resize()}else layui.each(c.that,function(){this.resize()})},d.reload=function(e,t){var i=s(e);if(i){var a=c.that[e];return a.reload(t),c.call(a)}},d.render=function(e){var t=new I(e);return c.call(t)},d.clearCacheKey=function(e){return e=t.extend({},e),delete e[d.config.checkName],delete e[d.config.indexName],e},d.init(),e(y,d)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/transfer.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define([\"laytpl\",\"form\"],function(e){\"use strict\";var a=layui.$,t=layui.laytpl,n=layui.form,i=\"transfer\",l={config:{},index:layui[i]?layui[i].index+1e4:0,set:function(e){var t=this;return t.config=a.extend({},t.config,e),t},on:function(e,a){return layui.onevent.call(this,i,e,a)}},r=function(){var e=this,a=e.config,t=a.id||e.index;return r.that[t]=e,r.config[t]=a,{config:a,reload:function(a){e.reload.call(e,a)},getData:function(){return e.getData.call(e)}}},c=\"layui-hide\",o=\"layui-btn-disabled\",d=\"layui-none\",s=\"layui-transfer-box\",u=\"layui-transfer-header\",h=\"layui-transfer-search\",f=\"layui-transfer-active\",y=\"layui-transfer-data\",p=function(e){return e=e||{},['<div class=\"layui-transfer-box\" data-index=\"'+e.index+'\">','<div class=\"layui-transfer-header\">','<input type=\"checkbox\" name=\"'+e.checkAllName+'\" lay-filter=\"layTransferCheckbox\" lay-type=\"all\" lay-skin=\"primary\" title=\"{{ d.data.title['+e.index+\"] || 'list\"+(e.index+1)+\"' }}\\\">\",\"</div>\",\"{{# if(d.data.showSearch){ }}\",'<div class=\"layui-transfer-search\">','<i class=\"layui-icon layui-icon-search\"></i>','<input type=\"input\" class=\"layui-input\" placeholder=\"关键词搜索\">',\"</div>\",\"{{# } }}\",'<ul class=\"layui-transfer-data\"></ul>',\"</div>\"].join(\"\")},v=['<div class=\"layui-transfer layui-form layui-border-box\" lay-filter=\"LAY-transfer-{{ d.index }}\">',p({index:0,checkAllName:\"layTransferLeftCheckAll\"}),'<div class=\"layui-transfer-active\">','<button type=\"button\" class=\"layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled\" data-index=\"0\">','<i class=\"layui-icon layui-icon-next\"></i>',\"</button>\",'<button type=\"button\" class=\"layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled\" data-index=\"1\">','<i class=\"layui-icon layui-icon-prev\"></i>',\"</button>\",\"</div>\",p({index:1,checkAllName:\"layTransferRightCheckAll\"}),\"</div>\"].join(\"\"),x=function(e){var t=this;t.index=++l.index,t.config=a.extend({},t.config,l.config,e),t.render()};x.prototype.config={title:[\"列表一\",\"列表二\"],width:200,height:360,data:[],value:[],showSearch:!1,id:\"\",text:{none:\"无数据\",searchNone:\"无匹配数据\"}},x.prototype.reload=function(e){var t=this;layui.each(e,function(e,a){a.constructor===Array&&delete t.config[e]}),t.config=a.extend(!0,{},t.config,e),t.render()},x.prototype.render=function(){var e=this,n=e.config,i=e.elem=a(t(v).render({data:n,index:e.index})),l=n.elem=a(n.elem);l[0]&&(n.data=n.data||[],n.value=n.value||[],e.key=n.id||e.index,l.html(e.elem),e.layBox=e.elem.find(\".\"+s),e.layHeader=e.elem.find(\".\"+u),e.laySearch=e.elem.find(\".\"+h),e.layData=i.find(\".\"+y),e.layBtn=i.find(\".\"+f+\" .layui-btn\"),e.layBox.css({width:n.width,height:n.height}),e.layData.css({height:function(){return n.height-e.layHeader.outerHeight()-e.laySearch.outerHeight()-2}()}),e.renderData(),e.events())},x.prototype.renderData=function(){var e=this,a=(e.config,[{checkName:\"layTransferLeftCheck\",views:[]},{checkName:\"layTransferRightCheck\",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,n=[\"<li>\",'<input type=\"checkbox\" name=\"'+a[t].checkName+'\" lay-skin=\"primary\" lay-filter=\"layTransferCheckbox\" title=\"'+e.title+'\"'+(e.disabled?\" disabled\":\"\")+(e.checked?\" checked\":\"\")+' value=\"'+e.value+'\">',\"</li>\"].join(\"\");a[t].views.push(n),delete e.selected}),e.layData.eq(0).html(a[0].views.join(\"\")),e.layData.eq(1).html(a[1].views.join(\"\")),e.renderCheckBtn()},x.prototype.renderForm=function(e){n.render(e,\"LAY-transfer-\"+this.index)},x.prototype.renderCheckBtn=function(e){var t=this,n=t.config;e=e||{},t.layBox.each(function(i){var l=a(this),r=l.find(\".\"+y),d=l.find(\".\"+u).find('input[type=\"checkbox\"]'),s=r.find('input[type=\"checkbox\"]'),h=0,f=!1;if(s.each(function(){var e=a(this).data(\"hide\");(this.checked||this.disabled||e)&&h++,this.checked&&!e&&(f=!0)}),d.prop(\"checked\",f&&h===s.length),t.layBtn.eq(i)[f?\"removeClass\":\"addClass\"](o),!e.stopNone){var p=r.children(\"li:not(.\"+c+\")\").length;t.noneView(r,p?\"\":n.text.none)}}),t.renderForm(\"checkbox\")},x.prototype.noneView=function(e,t){var n=a('<p class=\"layui-none\">'+(t||\"\")+\"</p>\");e.find(\".\"+d)[0]&&e.find(\".\"+d).remove(),t.replace(/\\s/g,\"\")&&e.append(n)},x.prototype.setValue=function(){var e=this,t=e.config,n=[];return e.layBox.eq(1).find(\".\"+y+' input[type=\"checkbox\"]').each(function(){var e=a(this).data(\"hide\");e||n.push(this.value)}),t.value=n,e},x.prototype.parseData=function(e){var t=this,n=t.config,i=[];return layui.each(n.data,function(t,l){l=(\"function\"==typeof n.parseData?n.parseData(l):l)||l,i.push(l=a.extend({},l)),layui.each(n.value,function(e,a){a==l.value&&(l.selected=!0)}),e&&e(l)}),n.data=i,t},x.prototype.getData=function(e){var a=this,t=a.config,n=[];return layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&n.push(t)})}),n},x.prototype.events=function(){var e=this,t=e.config;e.elem.on(\"click\",'input[lay-filter=\"layTransferCheckbox\"]+',function(){var t=a(this).prev(),n=t[0].checked,i=t.parents(\".\"+s).eq(0).find(\".\"+y);t[0].disabled||(\"all\"===t.attr(\"lay-type\")&&i.find('input[type=\"checkbox\"]').each(function(){this.disabled||(this.checked=n)}),e.renderCheckBtn({stopNone:!0}))}),e.layBtn.on(\"click\",function(){var n=a(this),i=n.data(\"index\"),l=e.layBox.eq(i),r=[];if(!n.hasClass(o)){e.layBox.eq(i).each(function(t){var n=a(this),i=n.find(\".\"+y);i.children(\"li\").each(function(){var t=a(this),n=t.find('input[type=\"checkbox\"]'),i=n.data(\"hide\");n[0].checked&&!i&&(n[0].checked=!1,l.siblings(\".\"+s).find(\".\"+y).append(t.clone()),t.remove(),r.push(n[0].value)),e.setValue()})}),e.renderCheckBtn();var c=l.siblings(\".\"+s).find(\".\"+h+\" input\");\"\"===c.val()||c.trigger(\"keyup\"),t.onchange&&t.onchange(e.getData(r),i)}}),e.laySearch.find(\"input\").on(\"keyup\",function(){var n=this.value,i=a(this).parents(\".\"+h).eq(0).siblings(\".\"+y),l=i.children(\"li\");l.each(function(){var e=a(this),t=e.find('input[type=\"checkbox\"]'),i=t[0].title.indexOf(n)!==-1;e[i?\"removeClass\":\"addClass\"](c),t.data(\"hide\",!i)}),e.renderCheckBtn();var r=l.length===i.children(\"li.\"+c).length;e.noneView(i,r?t.text.searchNone:\"\")})},r.that={},r.config={},l.reload=function(e,a){var t=r.that[e];return t.reload(a),r.call(t)},l.getData=function(e){var a=r.that[e];return a.getData()},l.render=function(e){var a=new x(e);return r.call(a)},e(i,l)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/tree.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"form\",function(e){\"use strict\";var i=layui.$,a=layui.form,n=\"tree\",r={config:{},index:layui[n]?layui[n].index+1e4:0,set:function(e){var a=this;return a.config=i.extend({},a.config,e),a},on:function(e,i){return layui.onevent.call(this,n,e,i)}},l=function(){var e=this,i=e.config,a=i.id||e.index;return l.that[a]=e,l.config[a]=i,{config:i,reload:function(i){e.reload.call(e,i)},getChecked:function(){return e.getChecked.call(e)},setChecked:function(i){return e.setChecked.call(e,i)}}},t=\"layui-hide\",d=\"layui-disabled\",s=\"layui-tree-set\",c=\"layui-tree-iconClick\",o=\"layui-icon-addition\",h=\"layui-icon-subtraction\",u=\"layui-tree-entry\",f=\"layui-tree-main\",p=\"layui-tree-txt\",y=\"layui-tree-pack\",v=\"layui-tree-spread\",C=\"layui-tree-setLineShort\",m=\"layui-tree-showLine\",k=\"layui-tree-lineExtend\",g=function(e){var a=this;a.index=++r.index,a.config=i.extend({},a.config,r.config,e),a.render()};g.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:\"未命名\",none:\"无数据\"}},g.prototype.reload=function(e){var a=this;layui.each(e,function(e,i){i.constructor===Array&&delete a.config[e]}),a.config=i.extend(!0,{},a.config,e),a.render()},g.prototype.render=function(){var e=this,a=e.config,n=i('<div class=\"layui-tree'+(a.showCheckbox?\" layui-form\":\"\")+(a.showLine?\" layui-tree-line\":\"\")+'\" lay-filter=\"LAY-tree-'+e.index+'\"></div>');e.tree(n);var r=a.elem=i(a.elem);if(r[0]){if(a.showSearch&&n.prepend('<input type=\"text\" class=\"layui-input layui-tree-search\" placeholder=\"请输入关键字进行过滤\">'),e.key=a.id||e.index,e.elem=n,e.elemNone=i('<div class=\"layui-tree-emptyText\">'+a.text.none+\"</div>\"),r.html(e.elem),0==e.elem.find(\".layui-tree-set\").length)return e.elem.append(e.elemNone);a.drag&&e.drag(),a.showCheckbox&&e.renderForm(\"checkbox\"),e.elem.find(\".layui-tree-set\").each(function(){var e=i(this);e.parent(\".layui-tree-pack\")[0]||e.addClass(\"layui-tree-setHide\"),!e.next()[0]&&e.parents(\".layui-tree-pack\").eq(1).hasClass(\"layui-tree-lineExtend\")&&e.addClass(C),e.next()[0]||e.parents(\".layui-tree-set\").eq(0).next()[0]||e.addClass(C)}),e.events()}},g.prototype.renderForm=function(e){a.render(e,\"LAY-tree-\"+this.index)},g.prototype.tree=function(e,a){var n=this,r=n.config,l=a||r.data;layui.each(l,function(a,l){var c=l.children&&l.children.length>0,o=i('<div class=\"layui-tree-pack\" '+(l.spread?'style=\"display: block;\"':\"\")+'\"></div>'),h=i(['<div data-id=\"'+l.id+'\" class=\"layui-tree-set'+(l.spread?\" layui-tree-spread\":\"\")+(l.checked?\" layui-tree-checkedFirst\":\"\")+'\">',\"<div \"+(r.drag&&!l.fixed?'draggable=\"true\"':\"\")+' class=\"layui-tree-entry\">','<div class=\"layui-tree-main\">',function(){return r.showLine?c?'<span class=\"layui-tree-iconClick layui-tree-icon\"><i class=\"layui-icon '+(l.spread?\"layui-icon-subtraction\":\"layui-icon-addition\")+'\"></i></span>':'<span class=\"layui-tree-iconClick\"><i class=\"layui-icon layui-icon-file\"></i></span>':'<span class=\"layui-tree-iconClick\"><i class=\"layui-tree-iconArrow '+(c?\"\":t)+'\"></i></span>'}(),function(){return r.showCheckbox?'<input type=\"checkbox\" name=\"layuiTreeCheck\" lay-skin=\"primary\" '+(l.disabled?\"disabled\":\"\")+'  value=\"'+l.id+'\">':\"\"}(),function(){return r.isJump&&l.href?'<a href=\"'+l.href+'\" target=\"_blank\" class=\"'+p+'\">'+(l.title||l.label||r.text.defaultNodeName)+\"</a>\":'<span class=\"'+p+(l.disabled?\" \"+d:\"\")+'\">'+(l.title||l.label||r.text.defaultNodeName)+\"</span>\"}(),\"</div>\",function(){if(!r.edit)return\"\";var e={add:'<i class=\"layui-icon layui-icon-add-1\"  data-type=\"add\"></i>',update:'<i class=\"layui-icon layui-icon-edit\" data-type=\"update\"></i>',del:'<i class=\"layui-icon layui-icon-delete\" data-type=\"del\"></i>'},i=['<div class=\"layui-btn-group layui-tree-btnGroup\">'];return r.edit===!0&&(r.edit=[\"update\",\"del\"]),\"object\"==typeof r.edit?(layui.each(r.edit,function(a,n){i.push(e[n]||\"\")}),i.join(\"\")+\"</div>\"):void 0}(),\"</div></div>\"].join(\"\"));c&&(h.append(o),n.tree(o,l.children)),e.append(h),h.prev(\".\"+s)[0]&&h.prev().children(\".layui-tree-pack\").addClass(\"layui-tree-showLine\"),c||h.parent(\".layui-tree-pack\").addClass(\"layui-tree-lineExtend\"),n.spread(h,l),r.showCheckbox&&n.checkClick(h,l),r.edit&&n.operate(h,l)})},g.prototype.spread=function(e,a){var n=this,r=n.config,l=e.children(\".\"+u),t=l.children(\".\"+f),C=l.find(\".\"+c),m=l.find(\".\"+p),k=r.onlyIconControl?C:t,g=\"\";k.on(\"click\",function(i){var a=e.children(\".\"+y),n=k.children(\".layui-icon\")[0]?k.children(\".layui-icon\"):k.find(\".layui-tree-icon\").children(\".layui-icon\");if(a[0]){if(e.hasClass(v))e.removeClass(v),a.slideUp(200),n.removeClass(h).addClass(o);else if(e.addClass(v),a.slideDown(200),n.addClass(h).removeClass(o),r.accordion){var l=e.siblings(\".\"+s);l.removeClass(v),l.children(\".\"+y).slideUp(200),l.find(\".layui-tree-icon\").children(\".layui-icon\").removeClass(h).addClass(o)}}else g=\"normal\"}),m.on(\"click\",function(){var n=i(this);n.hasClass(d)||(g=e.hasClass(v)?r.onlyIconControl?\"open\":\"close\":r.onlyIconControl?\"close\":\"open\",r.click&&r.click({elem:e,state:g,data:a}))})},g.prototype.setCheckbox=function(e,i,a){var n=this,r=(n.config,a.prop(\"checked\"));if(\"object\"==typeof i.children||e.find(\".\"+y)[0]){var l=e.find(\".\"+y).find('input[name=\"layuiTreeCheck\"]');l.each(function(){this.disabled||(this.checked=r)})}var t=function(e){if(e.parents(\".\"+s)[0]){var i,a=e.parent(\".\"+y),n=a.parent(),l=a.prev().find('input[name=\"layuiTreeCheck\"]');r?l.prop(\"checked\",r):(a.find('input[name=\"layuiTreeCheck\"]').each(function(){this.checked&&(i=!0)}),i||l.prop(\"checked\",!1)),t(n)}};t(e),n.renderForm(\"checkbox\")},g.prototype.checkClick=function(e,a){var n=this,r=n.config,l=e.children(\".\"+u),t=l.children(\".\"+f);t.on(\"click\",'input[name=\"layuiTreeCheck\"]+',function(l){layui.stope(l);var t=i(this).prev(),d=t.prop(\"checked\");t.prop(\"disabled\")||(n.setCheckbox(e,a,t),r.oncheck&&r.oncheck({elem:e,checked:d,data:a}))})},g.prototype.operate=function(e,a){var n=this,r=n.config,l=e.children(\".\"+u),d=l.children(\".\"+f);l.children(\".layui-tree-btnGroup\").on(\"click\",\".layui-icon\",function(l){layui.stope(l);var f=i(this).data(\"type\"),g=e.children(\".\"+y),x={data:a,type:f,elem:e};if(\"add\"==f){g[0]||(r.showLine?(d.find(\".\"+c).addClass(\"layui-tree-icon\"),d.find(\".\"+c).children(\".layui-icon\").addClass(o).removeClass(\"layui-icon-file\")):d.find(\".layui-tree-iconArrow\").removeClass(t),e.append('<div class=\"layui-tree-pack\"></div>'));var b=r.operate&&r.operate(x),w={};if(w.title=r.text.defaultNodeName,w.id=b,n.tree(e.children(\".\"+y),[w]),r.showLine)if(g[0])g.hasClass(k)||g.addClass(k),e.find(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)}),g.children(\".\"+s).last().prev().hasClass(C)?g.children(\".\"+s).last().prev().removeClass(C):g.children(\".\"+s).last().removeClass(C),!e.parent(\".\"+y)[0]&&e.next()[0]&&g.children(\".\"+s).last().removeClass(C);else{var T=e.siblings(\".\"+s),L=1,N=e.parent(\".\"+y);layui.each(T,function(e,a){i(a).children(\".\"+y)[0]||(L=0)}),1==L?(T.children(\".\"+y).addClass(m),T.children(\".\"+y).children(\".\"+s).removeClass(C),e.children(\".\"+y).addClass(m),N.removeClass(k),N.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C)):e.children(\".\"+y).children(\".\"+s).addClass(C)}if(!r.showCheckbox)return;if(d.find('input[name=\"layuiTreeCheck\"]')[0].checked){var A=e.children(\".\"+y).children(\".\"+s).last();A.find('input[name=\"layuiTreeCheck\"]')[0].checked=!0}n.renderForm(\"checkbox\")}else if(\"update\"==f){var q=d.children(\".\"+p).html();d.children(\".\"+p).html(\"\"),d.append('<input type=\"text\" class=\"layui-tree-editInput\">'),d.children(\".layui-tree-editInput\").val(q).focus();var F=function(e){var i=e.val().trim();i=i?i:r.text.defaultNodeName,e.remove(),d.children(\".\"+p).html(i),x.data.title=i,r.operate&&r.operate(x)};d.children(\".layui-tree-editInput\").blur(function(){F(i(this))}),d.children(\".layui-tree-editInput\").on(\"keydown\",function(e){13===e.keyCode&&(e.preventDefault(),F(i(this)))})}else{if(r.operate&&r.operate(x),x.status=\"remove\",!e.prev(\".\"+s)[0]&&!e.next(\".\"+s)[0]&&!e.parent(\".\"+y)[0])return e.remove(),void n.elem.append(n.elemNone);if(e.siblings(\".\"+s).children(\".\"+u)[0]){if(r.showCheckbox){var I=function(e){if(e.parents(\".\"+s)[0]){var a=e.siblings(\".\"+s).children(\".\"+u),r=e.parent(\".\"+y).prev(),l=r.find('input[name=\"layuiTreeCheck\"]')[0],t=1,d=0;0==l.checked&&(a.each(function(e,a){var n=i(a).find('input[name=\"layuiTreeCheck\"]')[0];0!=n.checked||n.disabled||(t=0),n.disabled||(d=1)}),1==t&&1==d&&(l.checked=!0,n.renderForm(\"checkbox\"),I(r.parent(\".\"+s))))}};I(e)}if(r.showLine){var T=e.siblings(\".\"+s),L=1,N=e.parent(\".\"+y);layui.each(T,function(e,a){i(a).children(\".\"+y)[0]||(L=0)}),1==L?(g[0]||(N.removeClass(k),T.children(\".\"+y).addClass(m),T.children(\".\"+y).children(\".\"+s).removeClass(C)),e.next()[0]?N.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C):e.prev().children(\".\"+y).children(\".\"+s).last().addClass(C),e.next()[0]||e.parents(\".\"+s)[1]||e.parents(\".\"+s).eq(0).next()[0]||e.prev(\".\"+s).addClass(C)):!e.next()[0]&&e.hasClass(C)&&e.prev().addClass(C)}}else{var H=e.parent(\".\"+y).prev();if(r.showLine){H.find(\".\"+c).removeClass(\"layui-tree-icon\"),H.find(\".\"+c).children(\".layui-icon\").removeClass(h).addClass(\"layui-icon-file\");var S=H.parents(\".\"+y).eq(0);S.addClass(k),S.children(\".\"+s).each(function(){i(this).children(\".\"+y).children(\".\"+s).last().addClass(C)})}else H.find(\".layui-tree-iconArrow\").addClass(t);e.parents(\".\"+s).eq(0).removeClass(v),e.parent(\".\"+y).remove()}e.remove()}})},g.prototype.drag=function(){var e=this,a=e.config;e.elem.on(\"dragstart\",\".\"+u,function(){var e=i(this).parent(\".\"+s),n=e.parents(\".\"+s)[0]?e.parents(\".\"+s).eq(0):\"未找到父节点\";a.dragstart&&a.dragstart(e,n)}),e.elem.on(\"dragend\",\".\"+u,function(n){var n=n||event,r=n.clientY,l=i(this),d=l.parent(\".\"+s),f=d.height(),p=d.offset().top,g=e.elem.find(\".\"+s),x=e.elem.height(),b=e.elem.offset().top,w=x+b-13,T=d.parents(\".\"+s)[0],L=d.next()[0];if(T)var N=d.parent(\".\"+y),A=d.parents(\".\"+s).eq(0),q=A.parent(\".\"+y),F=A.offset().top,I=d.siblings(),H=A.children(\".\"+y).children(\".\"+s).length;var S=function(n){if(T||L||e.elem.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C),!T)return void d.removeClass(\"layui-tree-setHide\");if(1==H)a.showLine?(n.find(\".\"+c).removeClass(\"layui-tree-icon\"),n.find(\".\"+c).children(\".layui-icon\").removeClass(h).addClass(\"layui-icon-file\"),q.addClass(k),q.children(\".\"+s).children(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)})):n.find(\".layui-tree-iconArrow\").addClass(t),n.children(\".\"+y).remove(),n.removeClass(v);else{if(a.showLine){var r=1;layui.each(I,function(e,a){i(a).children(\".\"+y)[0]||(r=0)}),1==r?(d.children(\".\"+y)[0]||(N.removeClass(k),I.children(\".\"+y).addClass(m),I.children(\".\"+y).children(\".\"+s).removeClass(C)),N.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C),L||n.parents(\".\"+s)[0]||n.next()[0]||N.children(\".\"+s).last().addClass(C)):!L&&d.hasClass(C)&&N.children(\".\"+s).last().addClass(C)}if(a.showCheckbox){var l=function(a){if(a){if(!a.parents(\".\"+s)[0])return}else if(!n[0])return;var r=a?a.siblings().children(\".\"+u):I.children(\".\"+u),t=a?a.parent(\".\"+y).prev():N.prev(),d=t.find('input[name=\"layuiTreeCheck\"]')[0],c=1,o=0;0==d.checked&&(r.each(function(e,a){var n=i(a).find('input[name=\"layuiTreeCheck\"]')[0];0!=n.checked||n.disabled||(c=0),n.disabled||(o=1)}),1==c&&1==o&&(d.checked=!0,e.renderForm(\"checkbox\"),l(t.parent(\".\"+s)||n)))};l()}}};g.each(function(){if(0!=i(this).height()){if(r>p&&r<p+f)return void(a.dragend&&a.dragend(\"drag error\"));if(1==H&&r>F&&r<p+f)return void(a.dragend&&a.dragend(\"drag error\"));var n=i(this).offset().top;if(r>n&&r<n+15){if(i(this).children(\".\"+y)[0]||(a.showLine?(i(this).find(\".\"+c).eq(0).addClass(\"layui-tree-icon\"),i(this).find(\".\"+c).eq(0).children(\".layui-icon\").addClass(o).removeClass(\"layui-icon-file\")):i(this).find(\".layui-tree-iconArrow\").removeClass(t),i(this).append('<div class=\"layui-tree-pack\"></div>')),i(this).children(\".\"+y).append(d),S(A),a.showLine){var l=i(this).children(\".\"+y).children(\".\"+s);if(d.children(\".\"+y).children(\".\"+s).last().addClass(C),1==l.length){var h=i(this).siblings(\".\"+s),v=1,g=i(this).parent(\".\"+y);layui.each(h,function(e,a){i(a).children(\".\"+y)[0]||(v=0)}),1==v?(h.children(\".\"+y).addClass(m),h.children(\".\"+y).children(\".\"+s).removeClass(C),i(this).children(\".\"+y).addClass(m),g.removeClass(k),g.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C).removeClass(\"layui-tree-setHide\")):i(this).children(\".\"+y).children(\".\"+s).addClass(C).removeClass(\"layui-tree-setHide\")}else d.prev(\".\"+s).hasClass(C)?(d.prev(\".\"+s).removeClass(C),d.addClass(C)):(d.removeClass(\"layui-tree-setLineShort layui-tree-setHide\"),d.children(\".\"+y)[0]?d.prev(\".\"+s).children(\".\"+y).children(\".\"+s).last().removeClass(C):d.siblings(\".\"+s).find(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)})),i(this).next()[0]||d.addClass(C)}if(a.showCheckbox&&i(this).children(\".\"+u).find('input[name=\"layuiTreeCheck\"]')[0].checked){var x=d.children(\".\"+u);x.find('input[name=\"layuiTreeCheck\"]+').click()}return a.dragend&&a.dragend(\"drag success\",d,i(this)),!1}if(r<n){if(i(this).before(d),S(A),a.showLine){var b=d.children(\".\"+y),T=i(this).parents(\".\"+s).eq(0),L=T.children(\".\"+y).children(\".\"+s).last();if(b[0]){d.removeClass(C),b.children(\".\"+s).last().removeClass(C);var h=d.siblings(\".\"+s),v=1;layui.each(h,function(e,a){i(a).children(\".\"+y)[0]||(v=0)}),1==v?T[0]&&(h.children(\".\"+y).addClass(m),h.children(\".\"+y).children(\".\"+s).removeClass(C),L.children(\".\"+y).children(\".\"+s).last().addClass(C).removeClass(m)):d.children(\".\"+y).children(\".\"+s).last().addClass(C),!T.parent(\".\"+y)[0]&&T.next()[0]&&L.removeClass(C)}else T.hasClass(k)||T.addClass(k),T.find(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)});T[0]||(d.addClass(\"layui-tree-setHide\"),d.children(\".\"+y).children(\".\"+s).last().removeClass(C))}if(T[0]&&a.showCheckbox&&T.children(\".\"+u).find('input[name=\"layuiTreeCheck\"]')[0].checked){var x=d.children(\".\"+u);x.find('input[name=\"layuiTreeCheck\"]+').click()}return a.dragend&&a.dragend(\"拖拽成功，插入目标节点上方\",d,i(this)),!1}if(r>w)return e.elem.children(\".\"+s).last().children(\".\"+y).addClass(m),e.elem.append(d),S(A),d.prev().children(\".\"+y).children(\".\"+s).last().removeClass(C),d.addClass(\"layui-tree-setHide\"),d.children(\".\"+y).children(\".\"+s).last().addClass(C),a.dragend&&a.dragend(\"拖拽成功，插入最外层节点\",d,e.elem),!1}})})},g.prototype.events=function(){var e=this,a=e.config,n=e.elem.find(\".layui-tree-checkedFirst\");layui.each(n,function(e,a){i(a).children(\".\"+u).find('input[name=\"layuiTreeCheck\"]+').trigger(\"click\")}),e.elem.find(\".layui-tree-search\").on(\"keyup\",function(){var n=i(this),r=n.val(),l=n.nextAll(),d=[];l.find(\".\"+p).each(function(){var e=i(this).parents(\".\"+u);if(i(this).html().indexOf(r)!=-1){d.push(i(this).parent());var a=function(e){e.addClass(\"layui-tree-searchShow\"),e.parent(\".\"+y)[0]&&a(e.parent(\".\"+y).parent(\".\"+s))};a(e.parent(\".\"+s))}}),l.find(\".\"+u).each(function(){var e=i(this).parent(\".\"+s);e.hasClass(\"layui-tree-searchShow\")||e.addClass(t)}),0==l.find(\".layui-tree-searchShow\").length&&e.elem.append(e.elemNone),a.onsearch&&a.onsearch({elem:d})}),e.elem.find(\".layui-tree-search\").on(\"keydown\",function(){i(this).nextAll().find(\".\"+u).each(function(){var e=i(this).parent(\".\"+s);e.removeClass(\"layui-tree-searchShow \"+t)}),i(\".layui-tree-emptyText\")[0]&&i(\".layui-tree-emptyText\").remove()})},g.prototype.getChecked=function(){var e=this,a=e.config,n=[],r=[];e.elem.find(\".layui-form-checked\").each(function(){n.push(i(this).prev()[0].value)});var l=function(e,a){layui.each(e,function(e,r){layui.each(n,function(e,n){if(r.id==n){var t=i.extend({},r);return delete t.children,a.push(t),r.children&&(t.children=[],l(r.children,t.children)),!0}})})};return l(i.extend({},a.data),r),r},g.prototype.setChecked=function(e){var a=this;a.config;a.elem.find(\".\"+s).each(function(a,n){var r=i(this).data(\"id\"),l=i(n).children(\".\"+u).find('input[name=\"layuiTreeCheck\"]'),t=l.next();if(\"number\"==typeof e){if(r==e)return l[0].checked||t.click(),!1}else i.inArray(r,e)!=-1&&(l[0].checked||t.click())})},l.that={},l.config={},r.reload=function(e,i){var a=l.that[e];return a.reload(i),l.call(a)},r.getChecked=function(e){var i=l.that[e];return i.getChecked()},r.setChecked=function(e,i){var a=l.that[e];return a.setChecked(i)},r.render=function(e){var i=new g(e);return l.call(i)},e(n,r)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/upload.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"layer\",function(e){\"use strict\";var t=layui.$,i=layui.layer,n=layui.hint(),a=layui.device(),o={config:{},set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,r,e,t)}},l=function(){var e=this;return{upload:function(t){e.upload.call(e,t)},reload:function(t){e.reload.call(e,t)},config:e.config}},r=\"upload\",u=\"layui-upload-file\",c=\"layui-upload-form\",f=\"layui-upload-iframe\",s=\"layui-upload-choose\",p=function(e){var i=this;i.config=t.extend({},i.config,o.config,e),i.render()};p.prototype.config={accept:\"images\",exts:\"\",auto:!0,bindAction:\"\",url:\"\",field:\"file\",acceptMime:\"\",method:\"post\",data:{},drag:!0,size:0,number:0,multiple:!1},p.prototype.render=function(e){var i=this,e=i.config;e.elem=t(e.elem),e.bindAction=t(e.bindAction),i.file(),i.events()},p.prototype.file=function(){var e=this,i=e.config,n=e.elemFile=t(['<input class=\"'+u+'\" type=\"file\" accept=\"'+i.acceptMime+'\" name=\"'+i.field+'\"',i.multiple?\" multiple\":\"\",\">\"].join(\"\")),o=i.elem.next();(o.hasClass(u)||o.hasClass(c))&&o.remove(),a.ie&&a.ie<10&&i.elem.wrap('<div class=\"layui-upload-wrap\"></div>'),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(n),a.ie&&a.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,i=e.config,n=t('<iframe id=\"'+f+'\" class=\"'+f+'\" name=\"'+f+'\" frameborder=\"0\"></iframe>'),a=t(['<form target=\"'+f+'\" class=\"'+c+'\" method=\"post\" key=\"set-mine\" enctype=\"multipart/form-data\" action=\"'+i.url+'\">',\"</form>\"].join(\"\"));t(\"#\"+f)[0]||t(\"body\").append(n),i.elem.next().hasClass(c)||(e.elemFile.wrap(a),i.elem.next(\".\"+c).append(function(){var e=[];return layui.each(i.data,function(t,i){i=\"function\"==typeof i?i():i,e.push('<input type=\"hidden\" name=\"'+t+'\" value=\"'+i+'\">')}),e.join(\"\")}()))},p.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return\"input\"===e.tagName.toLocaleLowerCase()&&\"file\"===e.type},p.prototype.preview=function(e){var t=this;window.FileReader&&layui.each(t.chooseFiles,function(t,i){var n=new FileReader;n.readAsDataURL(i),n.onload=function(){e&&e(t,i,this.result)}})},p.prototype.upload=function(e,i){var n,o=this,l=o.config,r=o.elemFile[0],u=function(){var i=0,n=0,a=e||o.files||o.chooseFiles||r.files,u=function(){l.multiple&&i+n===o.fileLength&&\"function\"==typeof l.allDone&&l.allDone({total:o.fileLength,successful:i,aborted:n})};layui.each(a,function(e,a){var r=new FormData;r.append(l.field,a),layui.each(l.data,function(e,t){t=\"function\"==typeof t?t():t,r.append(e,t)}),t.ajax({url:l.url,type:\"post\",data:r,contentType:!1,processData:!1,dataType:\"json\",headers:l.headers||{},success:function(t){i++,d(e,t),u()},error:function(){n++,o.msg(\"请求上传接口出现异常\"),m(e),u()}})})},c=function(){var e=t(\"#\"+f);o.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var t,i=e.contents().find(\"body\");try{t=i.text()}catch(n){o.msg(\"获取上传后的响应信息出现异常\"),clearInterval(p.timer),m()}t&&(clearInterval(p.timer),i.html(\"\"),d(0,t))},30)},d=function(e,t){if(o.elemFile.next(\".\"+s).remove(),r.value=\"\",\"object\"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},o.msg(\"请对上传接口返回有效JSON\")}\"function\"==typeof l.done&&l.done(t,e||0,function(e){o.upload(e)})},m=function(e){l.auto&&(r.value=\"\"),\"function\"==typeof l.error&&l.error(e||0,function(e){o.upload(e)})},h=l.exts,v=function(){var t=[];return layui.each(e||o.chooseFiles,function(e,i){t.push(i.name)}),t}(),g={preview:function(e){o.preview(e)},upload:function(e,t){var i={};i[e]=t,o.upload(i)},pushFile:function(){return o.files=o.files||{},layui.each(o.chooseFiles,function(e,t){o.files[e]=t}),o.files},resetFile:function(e,t,i){var n=new File([t],i);o.files=o.files||{},o.files[e]=n}},y=function(){if(\"choose\"!==i&&!l.auto||(l.choose&&l.choose(g),\"choose\"!==i))return l.before&&l.before(g),a.ie?a.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\\/\\\\]+\\..+/g)||[]||\"\":v,0!==v.length){switch(l.accept){case\"file\":if(h&&!RegExp(\"\\\\w\\\\.(\"+h+\")$\",\"i\").test(escape(v)))return o.msg(\"选择的文件中包含不支持的格式\"),r.value=\"\";break;case\"video\":if(!RegExp(\"\\\\w\\\\.(\"+(h||\"avi|mp4|wma|rmvb|rm|flash|3gp|flv\")+\")$\",\"i\").test(escape(v)))return o.msg(\"选择的视频中包含不支持的格式\"),r.value=\"\";break;case\"audio\":if(!RegExp(\"\\\\w\\\\.(\"+(h||\"mp3|wav|mid\")+\")$\",\"i\").test(escape(v)))return o.msg(\"选择的音频中包含不支持的格式\"),r.value=\"\";break;default:if(layui.each(v,function(e,t){RegExp(\"\\\\w\\\\.(\"+(h||\"jpg|png|gif|bmp|jpeg$\")+\")\",\"i\").test(escape(t))||(n=!0)}),n)return o.msg(\"选择的图片中包含不支持的格式\"),r.value=\"\"}if(o.fileLength=function(){var t=0,i=e||o.files||o.chooseFiles||r.files;return layui.each(i,function(){t++}),t}(),l.number&&o.fileLength>l.number)return o.msg(\"同时最多只能上传的数量为：\"+l.number);if(l.size>0&&!(a.ie&&a.ie<10)){var F;if(layui.each(o.chooseFiles,function(e,t){if(t.size>1024*l.size){var i=l.size/1024;i=i>=1?i.toFixed(2)+\"MB\":l.size+\"KB\",r.value=\"\",F=i}}),F)return o.msg(\"文件不能超过\"+F)}y()}},p.prototype.reload=function(e){e=e||{},delete e.elem,delete e.bindAction;var i=this,e=i.config=t.extend({},i.config,o.config,e),n=e.elem.next();n.attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},p.prototype.events=function(){var e=this,i=e.config,o=function(t){e.chooseFiles={},layui.each(t,function(t,i){var n=(new Date).getTime();e.chooseFiles[n+\"-\"+t]=i})},l=function(t,n){var a=e.elemFile,o=t.length>1?t.length+\"个文件\":(t[0]||{}).name||a[0].value.match(/[^\\/\\\\]+\\..+/g)||[]||\"\";a.next().hasClass(s)&&a.next().remove(),e.upload(null,\"choose\"),e.isFile()||i.choose||a.after('<span class=\"layui-inline '+s+'\">'+o+\"</span>\")};i.elem.off(\"upload.start\").on(\"upload.start\",function(){var a=t(this),o=a.attr(\"lay-data\");if(o)try{o=new Function(\"return \"+o)(),e.config=t.extend({},i,o)}catch(l){n.error(\"Upload element property lay-data configuration item has a syntax error: \"+o)}e.config.item=a,e.elemFile[0].click()}),a.ie&&a.ie<10||i.elem.off(\"upload.over\").on(\"upload.over\",function(){var e=t(this);e.attr(\"lay-over\",\"\")}).off(\"upload.leave\").on(\"upload.leave\",function(){var e=t(this);e.removeAttr(\"lay-over\")}).off(\"upload.drop\").on(\"upload.drop\",function(n,a){var r=t(this),u=a.originalEvent.dataTransfer.files||[];r.removeAttr(\"lay-over\"),o(u),i.auto?e.upload(u):l(u)}),e.elemFile.off(\"upload.change\").on(\"upload.change\",function(){var t=this.files||[];o(t),i.auto?e.upload():l(t)}),i.bindAction.off(\"upload.action\").on(\"upload.action\",function(){e.upload()}),i.elem.data(\"haveEvents\")||(e.elemFile.on(\"change\",function(){t(this).trigger(\"upload.change\")}),i.elem.on(\"click\",function(){e.isFile()||t(this).trigger(\"upload.start\")}),i.drag&&i.elem.on(\"dragover\",function(e){e.preventDefault(),t(this).trigger(\"upload.over\")}).on(\"dragleave\",function(e){t(this).trigger(\"upload.leave\")}).on(\"drop\",function(e){e.preventDefault(),t(this).trigger(\"upload.drop\",e)}),i.bindAction.on(\"click\",function(){t(this).trigger(\"upload.action\")}),i.elem.data(\"haveEvents\",!0))},o.render=function(e){var t=new p(e);return l.call(t)},e(r,o)});"
  },
  {
    "path": "src/main/webapp/static/layui/lay/modules/util.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;layui.define(\"jquery\",function(t){\"use strict\";var e=layui.$,i={fixbar:function(t){var i,n,a=\"layui-fixbar\",o=\"layui-fixbar-top\",r=e(document),l=e(\"body\");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?\"&#xe606;\":t.bar1,t.bar2=t.bar2===!0?\"&#xe607;\":t.bar2,t.bgcolor=t.bgcolor?\"background-color:\"+t.bgcolor:\"\";var c=[t.bar1,t.bar2,\"&#xe604;\"],g=e(['<ul class=\"'+a+'\">',t.bar1?'<li class=\"layui-icon\" lay-type=\"bar1\" style=\"'+t.bgcolor+'\">'+c[0]+\"</li>\":\"\",t.bar2?'<li class=\"layui-icon\" lay-type=\"bar2\" style=\"'+t.bgcolor+'\">'+c[1]+\"</li>\":\"\",'<li class=\"layui-icon '+o+'\" lay-type=\"top\" style=\"'+t.bgcolor+'\">'+c[2]+\"</li>\",\"</ul>\"].join(\"\")),s=g.find(\".\"+o),u=function(){var e=r.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e(\".\"+a)[0]||(\"object\"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find(\"li\").on(\"click\",function(){var i=e(this),n=i.attr(\"lay-type\");\"top\"===n&&e(\"html,body\").animate({scrollTop:0},200),t.click&&t.click.call(this,n)}),r.on(\"scroll\",function(){clearTimeout(n),n=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var n=this,a=\"function\"==typeof e,o=new Date(t).getTime(),r=new Date(!e||a?(new Date).getTime():e).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=e);var g=setTimeout(function(){n.countdown(t,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(t).getTime();return a>6912e5?(a=new Date(t),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),e||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join(\"-\")+\" \"+n[1].join(\":\")):a>=864e5?(a/1e3/60/60/24|0)+\"天前\":a>=36e5?(a/1e3/60/60|0)+\"小时前\":a>=12e4?(a/1e3/60|0)+\"分钟前\":a<0?\"未来\":\"刚刚\"},digit:function(t,e){var i=\"\";t=String(t),e=e||2;for(var n=t.length;n<e;n++)i+=\"0\";return t<Math.pow(10,e)?i+(0|t):t},toDateString:function(t,e){var i=this,n=new Date(t||new Date),a=[i.digit(n.getFullYear(),4),i.digit(n.getMonth()+1),i.digit(n.getDate())],o=[i.digit(n.getHours()),i.digit(n.getMinutes()),i.digit(n.getSeconds())];return e=e||\"yyyy-MM-dd HH:mm:ss\",e.replace(/yyyy/g,a[0]).replace(/MM/g,a[1]).replace(/dd/g,a[2]).replace(/HH/g,o[0]).replace(/mm/g,o[1]).replace(/ss/g,o[2])},escape:function(t){return String(t||\"\").replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")},event:function(t,n,a){n=i.event[t]=e.extend(!0,i.event[t],n)||{},e(\"body\").on(a||\"click\",\"*[\"+t+\"]\",function(){var i=e(this),a=i.attr(t);n[a]&&n[a].call(this,i)})}};!function(t,e,i){\"$:nomunge\";function n(){a=e[l](function(){o.each(function(){var e=t(this),i=e.width(),n=e.height(),a=t.data(this,g);(i!==a.w||n!==a.h)&&e.trigger(c,[a.w=i,a.h=n])}),n()},r[s])}var a,o=t([]),r=t.resize=t.extend(t.resize,{}),l=\"setTimeout\",c=\"resize\",g=c+\"-special-event\",s=\"delay\",u=\"throttleWindow\";r[s]=250,r[u]=!0,t.event.special[c]={setup:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===o.length&&n()},teardown:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.not(e),e.removeData(g),o.length||clearTimeout(a)},add:function(e){function n(e,n,o){var r=t(this),l=t.data(this,g)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[u]&&this[l])return!1;var a;return t.isFunction(e)?(a=e,n):(a=e.handler,void(e.handler=n))}}}(e,window),t(\"util\",i)});"
  },
  {
    "path": "src/main/webapp/static/layui/layui.all.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;!function(e){\"use strict\";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v=\"2.5.4\"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if(\"interactive\"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),i=function(t){e.console&&console.error&&console.error(\"Layui hint: \"+t)},a=\"undefined\"!=typeof opera&&\"[object Opera]\"===opera.toString(),u={layer:\"modules/layer\",laydate:\"modules/laydate\",laypage:\"modules/laypage\",laytpl:\"modules/laytpl\",layim:\"modules/layim\",layedit:\"modules/layedit\",form:\"modules/form\",upload:\"modules/upload\",transfer:\"modules/transfer\",tree:\"modules/tree\",table:\"modules/table\",element:\"modules/element\",rate:\"modules/rate\",colorpicker:\"modules/colorpicker\",slider:\"modules/slider\",carousel:\"modules/carousel\",flow:\"modules/flow\",util:\"modules/util\",code:\"modules/code\",jquery:\"modules/jquery\",mobile:\"modules/mobile\",\"layui.all\":\"../layui.all\"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r=\"function\"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return\"function\"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),!layui[\"layui.all\"]&&layui[\"layui.mobile\"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n=\"PLaySTATION 3\"===navigator.platform?/^complete$/:/^(complete|loaded)$/;(\"load\"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+\" is not a valid module\"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):\"function\"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName(\"head\")[0];e=\"string\"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){\"jquery\"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\\/\\/([\\s\\S]+?)\\//)||[\"//\"+location.host+\"/\"])[0],0===e.length||layui[\"layui.all\"]&&u[f]||!layui[\"layui.all\"]&&layui[\"layui.mobile\"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+\" is not a valid module\"):void(\"string\"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement(\"script\"),h=(u[f]?p+\"lay/\":/^\\{\\/\\}/.test(y.modules[f])?\"\":o.base||\"\")+(y.modules[f]||f)+\".js\";h=h.replace(/^\\{\\/\\}/,\"\"),v.async=!0,v.charset=\"utf-8\",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||\"\";return e?\"?v=\"+e:\"\"}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf(\"[native code\")<0||a?v.addEventListener(\"load\",function(e){s(e,h)},!1):v.attachEvent(\"onreadystatechange\",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement(\"link\"),l=t.getElementsByTagName(\"head\")[0];\"string\"==typeof n&&(r=n);var s=(r||e).replace(/\\.|\\//g,\"\"),c=u.id=\"layuicss-\"+s,y=0;return u.rel=\"stylesheet\",u.href=e+(o.debug?\"?v=\"+(new Date).getTime():\"\"),u.media=\"all\",t.getElementById(c)||l.appendChild(u),\"function\"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+\" timeout\"):void(1989===parseInt(a.getStyle(t.getElementById(c),\"width\"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return\"function\"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+\"css/\"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,\"function\"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,\"function\"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i(\"模块名 \"+o+\" 已被占用\"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||\"\"};return/^#\\//.test(e)?(e=e.replace(/^#\\//,\"\"),o.href=\"/\"+e,e=e.replace(/([^#])(#.*$)/,\"$1\").split(\"/\")||[],t.each(e,function(e,t){/^\\w+=/.test(t)?function(){t=t.split(\"=\"),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||\"layui\",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o=\"object\"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return\"value\"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+\"/([^\\\\s\\\\_\\\\-]+)\");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?\"windows\":/linux/.test(o)?\"linux\":/iphone|ipod|ipad|ios/.test(o)?\"ios\":/mac/.test(o)?\"mac\":void 0}(),ie:function(){return!!(e.ActiveXObject||\"ActiveXObject\"in e)&&((o.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),weixin:n(\"micromessenger\")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios=\"ios\"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if(\"function\"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;o<e.length&&!t.call(e[o],o,e[o]);o++);return n},n.prototype.sort=function(e,t,o){var n=JSON.parse(JSON.stringify(e||[]));return t?(n.sort(function(e,o){var n=/^-?\\d+$/,r=e[t],i=o[t];return n.test(r)&&(r=parseFloat(r)),n.test(i)&&(i=parseFloat(i)),r&&!i?1:!r&&i?-1:r>i?1:r<i?-1:0}),o&&n.reverse(),n):n},n.prototype.stope=function(t){t=t||e.event;try{t.stopPropagation()}catch(o){t.cancelBubble=!0}},n.prototype.onevent=function(e,t,o){return\"string\"!=typeof e||\"function\"!=typeof o?this:n.event(e,t,null,o)},n.prototype.event=n.event=function(e,t,n,r){var i=this,a=null,u=t.match(/\\((.*)\\)$/)||[],l=(e+\".\"+t).replace(u[0],\"\"),s=u[1]||\"\",c=function(e,t){var o=t&&t.call(i,n);o===!1&&null===a&&(a=!1)};return r?(o.event[l]=o.event[l]||{},o.event[l][s]=[r],this):(layui.each(o.event[l],function(e,t){return\"{*}\"===s?void layui.each(t,c):(\"\"===e&&layui.each(t,c),void(s&&e===s&&layui.each(t,c)))}),a)},e.layui=new n}(window);layui.define(function(a){var i=layui.cache;layui.config({dir:i.dir.replace(/lay\\/dest\\/$/,\"\")}),a(\"layui.all\",layui.v)});layui.define(function(e){\"use strict\";var r={open:\"{{\",close:\"}}\"},c={exp:function(e){return new RegExp(e,\"g\")},query:function(e,c,t){var o=[\"#([\\\\s\\\\S])+?\",\"([^{#}])*?\"][e||0];return n((c||\"\")+r.open+o+r.close+(t||\"\"))},escape:function(e){return String(e||\"\").replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")},error:function(e,r){var c=\"Laytpl Error：\";return\"object\"==typeof console&&console.error(c+e+\"\\n\"+(r||\"\")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n(\"^\"+r.open+\"#\",\"\"),l=n(r.close+\"$\",\"\");e=e.replace(/\\s+|\\r|\\t|\\n/g,\" \").replace(n(r.open+\"#\"),r.open+\"# \").replace(n(r.close+\"}\"),\"} \"+r.close).replace(/\\\\/g,\"\\\\\\\\\").replace(n(r.open+\"!(.+?)!\"+r.close),function(e){return e=e.replace(n(\"^\"+r.open+\"!\"),\"\").replace(n(\"!\"+r.close),\"\").replace(n(r.open+\"|\"+r.close),function(e){return e.replace(/(.)/g,\"\\\\$1\")})}).replace(/(?=\"|')/g,\"\\\\\").replace(c.query(),function(e){return e=e.replace(a,\"\").replace(l,\"\"),'\";'+e.replace(/\\\\/g,\"\")+';view+=\"'}).replace(c.query(1),function(e){var c='\"+(';return e.replace(/\\s/g,\"\")===r.open+r.close?\"\":(e=e.replace(n(r.open+\"|\"+r.close),\"\"),/^=/.test(e)&&(e=e.replace(/^=/,\"\"),c='\"+_escape_('),c+e.replace(/\\\\/g,\"\")+')+\"')}),e='\"use strict\";var view = \"'+e+'\";return view;';try{return o.cache=e=new Function(\"d, _escape_\",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error(\"no data\")};var o=function(e){return\"string\"!=typeof e?c.error(\"Template not found\"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v=\"1.2.0\",e(\"laytpl\",o)});layui.define(function(e){\"use strict\";var a=document,t=\"getElementById\",n=\"getElementsByTagName\",i=\"laypage\",r=\"layui-disabled\",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if(\"object\"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups=\"groups\"in a?0|a.groups:5;a.layout=\"object\"==typeof a.layout?a.layout:[\"prev\",\"page\",\"next\"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits=\"object\"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev=\"prev\"in a?a.prev:\"&#x4E0A;&#x4E00;&#x9875;\",a.next=\"next\"in a?a.next:\"&#x4E0B;&#x4E00;&#x9875;\";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?'<a href=\"javascript:;\" class=\"layui-laypage-prev'+(1==a.curr?\" \"+r:\"\")+'\" data-page=\"'+(a.curr-1)+'\">'+a.prev+\"</a>\":\"\"}(),page:function(){var e=[];if(a.count<1)return\"\";n>1&&a.first!==!1&&0!==t&&e.push('<a href=\"javascript:;\" class=\"layui-laypage-first\" data-page=\"1\"  title=\"&#x9996;&#x9875;\">'+(a.first||1)+\"</a>\");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r<t-1&&(r=u-t+1),a.first!==!1&&r>2&&e.push('<span class=\"layui-laypage-spr\">&#x2026;</span>');r<=u;r++)r===a.curr?e.push('<span class=\"layui-laypage-curr\"><em class=\"layui-laypage-em\" '+(/^#/.test(a.theme)?'style=\"background-color:'+a.theme+';\"':\"\")+\"></em><em>\"+r+\"</em></span>\"):e.push('<a href=\"javascript:;\" data-page=\"'+r+'\">'+r+\"</a>\");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1<a.pages&&e.push('<span class=\"layui-laypage-spr\">&#x2026;</span>'),0!==t&&e.push('<a href=\"javascript:;\" class=\"layui-laypage-last\" title=\"&#x5C3E;&#x9875;\"  data-page=\"'+a.pages+'\">'+(a.last||a.pages)+\"</a>\")),e.join(\"\")}(),next:function(){return a.next?'<a href=\"javascript:;\" class=\"layui-laypage-next'+(a.curr==a.pages?\" \"+r:\"\")+'\" data-page=\"'+(a.curr+1)+'\">'+a.next+\"</a>\":\"\"}(),count:'<span class=\"layui-laypage-count\">共 '+a.count+\" 条</span>\",limit:function(){var e=['<span class=\"layui-laypage-limits\"><select lay-ignore>'];return layui.each(a.limits,function(t,n){e.push('<option value=\"'+n+'\"'+(n===a.limit?\"selected\":\"\")+\">\"+n+\" 条/页</option>\")}),e.join(\"\")+\"</select></span>\"}(),refresh:['<a href=\"javascript:;\" data-page=\"'+a.curr+'\" class=\"layui-laypage-refresh\">','<i class=\"layui-icon layui-icon-refresh\"></i>',\"</a>\"].join(\"\"),skip:function(){return['<span class=\"layui-laypage-skip\">&#x5230;&#x7B2C;','<input type=\"text\" min=\"1\" value=\"'+a.curr+'\" class=\"layui-input\">','&#x9875;<button type=\"button\" class=\"layui-laypage-btn\">&#x786e;&#x5b9a;</button>',\"</span>\"].join(\"\")}()};return['<div class=\"layui-box layui-laypage layui-laypage-'+(a.theme?/^#/.test(a.theme)?\"molv\":a.theme:\"default\")+'\" id=\"layui-laypage-'+a.index+'\">',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join(\"\")}(),\"</div>\"].join(\"\")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n](\"button\")[0],l=e[n](\"input\")[0],p=e[n](\"select\")[0],c=function(){var e=0|l.value.replace(/\\s|\\D/g,\"\");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;o<y;o++)\"a\"===r[o].nodeName.toLowerCase()&&s.on(r[o],\"click\",function(){var e=0|this.getAttribute(\"data-page\");e<1||e>i.pages||(i.curr=e,t.render())});p&&s.on(p,\"change\",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,\"click\",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n](\"input\")[0];t&&s.on(t,\"keyup\",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\\D/.test(n)&&(this.value=n.replace(/\\D/,\"\")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t](\"layui-laypage-\"+i.index);n.jump(s),i.hash&&!e&&(location.hash=\"!\"+i.hash+\"=\"+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent(\"on\"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});!function(){\"use strict\";var e=window.layui&&layui.define,t={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,n=t.length-1,a=n;a>0;a--)if(\"interactive\"===t[a].readyState){e=t[a].src;break}return e||t[n].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),getStyle:function(e,t){var n=e.currentStyle?e.currentStyle:window.getComputedStyle(e,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](t)},link:function(e,a,i){if(n.path){var r=document.getElementsByTagName(\"head\")[0],o=document.createElement(\"link\");\"string\"==typeof a&&(i=a);var s=(i||e).replace(/\\.|\\//g,\"\"),l=\"layuicss-\"+s,d=0;o.rel=\"stylesheet\",o.href=n.path+e,o.id=l,document.getElementById(l)||r.appendChild(o),\"function\"==typeof a&&!function c(){return++d>80?window.console&&console.error(\"laydate.css: Invalid\"):void(1989===parseInt(t.getStyle(document.getElementById(l),\"width\"))?a():setTimeout(c,100))}()}}},n={v:\"5.0.9\",config:{},index:window.laydate&&window.laydate.v?1e5:0,path:t.getPath,set:function(e){var t=this;return t.config=w.extend({},t.config,e),t},ready:function(a){var i=\"laydate\",r=\"\",o=(e?\"modules/laydate/\":\"theme/\")+\"default/laydate.css?v=\"+n.v+r;return e?layui.addcss(o,a,i):t.link(o,a,i),this}},a=function(){var e=this;return{hint:function(t){e.hint.call(e,t)},config:e.config}},i=\"laydate\",r=\".layui-laydate\",o=\"layui-this\",s=\"laydate-disabled\",l=\"开始日期超出了结束日期<br>建议重新选择\",d=[100,2e5],c=\"layui-laydate-static\",m=\"layui-laydate-list\",u=\"laydate-selected\",h=\"layui-laydate-hint\",y=\"laydate-day-prev\",f=\"laydate-day-next\",p=\"layui-laydate-footer\",g=\".laydate-btns-confirm\",v=\"laydate-time-text\",D=\".laydate-btns-time\",T=function(e){var t=this;t.index=++n.index,t.config=w.extend({},t.config,n.config,e),n.ready(function(){t.init()})},w=function(e){return new C(e)},C=function(e){for(var t=0,n=\"object\"==typeof e?[e]:(this.selector=e,document.querySelectorAll(e||null));t<n.length;t++)this.push(n[t])};C.prototype=[],C.prototype.constructor=C,w.extend=function(){var e=1,t=arguments,n=function(e,t){e=e||(t.constructor===Array?[]:{});for(var a in t)e[a]=t[a]&&t[a].constructor===Object?n(e[a],t[a]):t[a];return e};for(t[0]=\"object\"==typeof t[0]?t[0]:{};e<t.length;e++)\"object\"==typeof t[e]&&n(t[0],t[e]);return t[0]},w.ie=function(){var e=navigator.userAgent.toLowerCase();return!!(window.ActiveXObject||\"ActiveXObject\"in window)&&((e.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),w.stope=function(e){e=e||window.event,e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},w.each=function(e,t){var n,a=this;if(\"function\"!=typeof t)return a;if(e=e||[],e.constructor===Object){for(n in e)if(t.call(e[n],n,e[n]))break}else for(n=0;n<e.length&&!t.call(e[n],n,e[n]);n++);return a},w.digit=function(e,t,n){var a=\"\";e=String(e),t=t||2;for(var i=e.length;i<t;i++)a+=\"0\";return e<Math.pow(10,t)?a+(0|e):e},w.elem=function(e,t){var n=document.createElement(e);return w.each(t||{},function(e,t){n.setAttribute(e,t)}),n},C.addStr=function(e,t){return e=e.replace(/\\s+/,\" \"),t=t.replace(/\\s+/,\" \").split(\" \"),w.each(t,function(t,n){new RegExp(\"\\\\b\"+n+\"\\\\b\").test(e)||(e=e+\" \"+n)}),e.replace(/^\\s|\\s$/,\"\")},C.removeStr=function(e,t){return e=e.replace(/\\s+/,\" \"),t=t.replace(/\\s+/,\" \").split(\" \"),w.each(t,function(t,n){var a=new RegExp(\"\\\\b\"+n+\"\\\\b\");a.test(e)&&(e=e.replace(a,\"\"))}),e.replace(/\\s+/,\" \").replace(/^\\s|\\s$/,\"\")},C.prototype.find=function(e){var t=this,n=0,a=[],i=\"object\"==typeof e;return this.each(function(r,o){for(var s=i?[e]:o.querySelectorAll(e||null);n<s.length;n++)a.push(s[n]);t.shift()}),i||(t.selector=(t.selector?t.selector+\" \":\"\")+e),w.each(a,function(e,n){t.push(n)}),t},C.prototype.each=function(e){return w.each.call(this,this,e)},C.prototype.addClass=function(e,t){return this.each(function(n,a){a.className=C[t?\"removeStr\":\"addStr\"](a.className,e)})},C.prototype.removeClass=function(e){return this.addClass(e,!0)},C.prototype.hasClass=function(e){var t=!1;return this.each(function(n,a){new RegExp(\"\\\\b\"+e+\"\\\\b\").test(a.className)&&(t=!0)}),t},C.prototype.attr=function(e,t){var n=this;return void 0===t?function(){if(n.length>0)return n[0].getAttribute(e)}():n.each(function(n,a){a.setAttribute(e,t)})},C.prototype.removeAttr=function(e){return this.each(function(t,n){n.removeAttribute(e)})},C.prototype.html=function(e){return this.each(function(t,n){n.innerHTML=e})},C.prototype.val=function(e){return this.each(function(t,n){n.value=e})},C.prototype.append=function(e){return this.each(function(t,n){\"object\"==typeof e?n.appendChild(e):n.innerHTML=n.innerHTML+e})},C.prototype.remove=function(e){return this.each(function(t,n){e?n.removeChild(e):n.parentNode.removeChild(n)})},C.prototype.on=function(e,t){return this.each(function(n,a){a.attachEvent?a.attachEvent(\"on\"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1)})},C.prototype.off=function(e,t){return this.each(function(n,a){a.detachEvent?a.detachEvent(\"on\"+e,t):a.removeEventListener(e,t,!1)})},T.isLeapYear=function(e){return e%4===0&&e%100!==0||e%400===0},T.prototype.config={type:\"date\",range:!1,format:\"yyyy-MM-dd\",value:null,isInitValue:!0,min:\"1900-1-1\",max:\"2099-12-31\",trigger:\"focus\",show:!1,showBottom:!0,btns:[\"clear\",\"now\",\"confirm\"],lang:\"cn\",theme:\"default\",position:null,calendar:!1,mark:{},zIndex:null,done:null,change:null},T.prototype.lang=function(){var e=this,t=e.config,n={cn:{weeks:[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],time:[\"时\",\"分\",\"秒\"],timeTips:\"选择时间\",startTime:\"开始时间\",endTime:\"结束时间\",dateTips:\"返回日期\",month:[\"一\",\"二\",\"三\",\"四\",\"五\",\"六\",\"七\",\"八\",\"九\",\"十\",\"十一\",\"十二\"],tools:{confirm:\"确定\",clear:\"清空\",now:\"现在\"}},en:{weeks:[\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"],time:[\"Hours\",\"Minutes\",\"Seconds\"],timeTips:\"Select Time\",startTime:\"Start Time\",endTime:\"End Time\",dateTips:\"Select Date\",month:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],tools:{confirm:\"Confirm\",clear:\"Clear\",now:\"Now\"}}};return n[t.lang]||n.cn},T.prototype.init=function(){var e=this,t=e.config,n=\"yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s\",a=\"static\"===t.position,i={year:\"yyyy\",month:\"yyyy-MM\",date:\"yyyy-MM-dd\",time:\"HH:mm:ss\",datetime:\"yyyy-MM-dd HH:mm:ss\"};t.elem=w(t.elem),t.eventElem=w(t.eventElem),t.elem[0]&&(t.range===!0&&(t.range=\"-\"),t.format===i.date&&(t.format=i[t.type]),e.format=t.format.match(new RegExp(n+\"|.\",\"g\"))||[],e.EXP_IF=\"\",e.EXP_SPLIT=\"\",w.each(e.format,function(t,a){var i=new RegExp(n).test(a)?\"\\\\d{\"+function(){return new RegExp(n).test(e.format[0===t?t+1:t-1]||\"\")?/^yyyy|y$/.test(a)?4:a.length:/^yyyy$/.test(a)?\"1,4\":/^y$/.test(a)?\"1,308\":\"1,2\"}()+\"}\":\"\\\\\"+a;e.EXP_IF=e.EXP_IF+i,e.EXP_SPLIT=e.EXP_SPLIT+\"(\"+i+\")\"}),e.EXP_IF=new RegExp(\"^\"+(t.range?e.EXP_IF+\"\\\\s\\\\\"+t.range+\"\\\\s\"+e.EXP_IF:e.EXP_IF)+\"$\"),e.EXP_SPLIT=new RegExp(\"^\"+e.EXP_SPLIT+\"$\",\"\"),e.isInput(t.elem[0])||\"focus\"===t.trigger&&(t.trigger=\"click\"),t.elem.attr(\"lay-key\")||(t.elem.attr(\"lay-key\",e.index),t.eventElem.attr(\"lay-key\",e.index)),t.mark=w.extend({},t.calendar&&\"cn\"===t.lang?{\"0-1-1\":\"元旦\",\"0-2-14\":\"情人\",\"0-3-8\":\"妇女\",\"0-3-12\":\"植树\",\"0-4-1\":\"愚人\",\"0-5-1\":\"劳动\",\"0-5-4\":\"青年\",\"0-6-1\":\"儿童\",\"0-9-10\":\"教师\",\"0-9-18\":\"国耻\",\"0-10-1\":\"国庆\",\"0-12-25\":\"圣诞\"}:{},t.mark),w.each([\"min\",\"max\"],function(e,n){var a=[],i=[];if(\"number\"==typeof t[n]){var r=t[n],o=(new Date).getTime(),s=864e5,l=new Date(r?r<s?o+r*s:r:o);a=[l.getFullYear(),l.getMonth()+1,l.getDate()],r<s||(i=[l.getHours(),l.getMinutes(),l.getSeconds()])}else a=(t[n].match(/\\d+-\\d+-\\d+/)||[\"\"])[0].split(\"-\"),i=(t[n].match(/\\d+:\\d+:\\d+/)||[\"\"])[0].split(\":\");t[n]={year:0|a[0]||(new Date).getFullYear(),month:a[1]?(0|a[1])-1:(new Date).getMonth(),date:0|a[2]||(new Date).getDate(),hours:0|i[0],minutes:0|i[1],seconds:0|i[2]}}),e.elemID=\"layui-laydate\"+t.elem.attr(\"lay-key\"),(t.show||a)&&e.render(),a||e.events(),t.value&&t.isInitValue&&(t.value.constructor===Date?e.setValue(e.parse(0,e.systemDate(t.value))):e.setValue(t.value)))},T.prototype.render=function(){var e=this,t=e.config,n=e.lang(),a=\"static\"===t.position,i=e.elem=w.elem(\"div\",{id:e.elemID,\"class\":[\"layui-laydate\",t.range?\" layui-laydate-range\":\"\",a?\" \"+c:\"\",t.theme&&\"default\"!==t.theme&&!/^#/.test(t.theme)?\" laydate-theme-\"+t.theme:\"\"].join(\"\")}),r=e.elemMain=[],o=e.elemHeader=[],s=e.elemCont=[],l=e.table=[],d=e.footer=w.elem(\"div\",{\"class\":p});if(t.zIndex&&(i.style.zIndex=t.zIndex),w.each(new Array(2),function(e){if(!t.range&&e>0)return!0;var a=w.elem(\"div\",{\"class\":\"layui-laydate-header\"}),i=[function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-y\"});return e.innerHTML=\"&#xe65a;\",e}(),function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-m\"});return e.innerHTML=\"&#xe603;\",e}(),function(){var e=w.elem(\"div\",{\"class\":\"laydate-set-ym\"}),t=w.elem(\"span\"),n=w.elem(\"span\");return e.appendChild(t),e.appendChild(n),e}(),function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-m\"});return e.innerHTML=\"&#xe602;\",e}(),function(){var e=w.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-y\"});return e.innerHTML=\"&#xe65b;\",e}()],d=w.elem(\"div\",{\"class\":\"layui-laydate-content\"}),c=w.elem(\"table\"),m=w.elem(\"thead\"),u=w.elem(\"tr\");w.each(i,function(e,t){a.appendChild(t)}),m.appendChild(u),w.each(new Array(6),function(e){var t=c.insertRow(0);w.each(new Array(7),function(a){if(0===e){var i=w.elem(\"th\");i.innerHTML=n.weeks[a],u.appendChild(i)}t.insertCell(a)})}),c.insertBefore(m,c.children[0]),d.appendChild(c),r[e]=w.elem(\"div\",{\"class\":\"layui-laydate-main laydate-main-list-\"+e}),r[e].appendChild(a),r[e].appendChild(d),o.push(i),s.push(d),l.push(c)}),w(d).html(function(){var e=[],i=[];return\"datetime\"===t.type&&e.push('<span lay-type=\"datetime\" class=\"laydate-btns-time\">'+n.timeTips+\"</span>\"),w.each(t.btns,function(e,r){var o=n.tools[r]||\"btn\";t.range&&\"now\"===r||(a&&\"clear\"===r&&(o=\"cn\"===t.lang?\"重置\":\"Reset\"),i.push('<span lay-type=\"'+r+'\" class=\"laydate-btns-'+r+'\">'+o+\"</span>\"))}),e.push('<div class=\"laydate-footer-btns\">'+i.join(\"\")+\"</div>\"),e.join(\"\")}()),w.each(r,function(e,t){i.appendChild(t)}),t.showBottom&&i.appendChild(d),/^#/.test(t.theme)){var m=w.elem(\"style\"),u=[\"#{{id}} .layui-laydate-header{background-color:{{theme}};}\",\"#{{id}} .layui-this{background-color:{{theme}} !important;}\"].join(\"\").replace(/{{id}}/g,e.elemID).replace(/{{theme}}/g,t.theme);\"styleSheet\"in m?(m.setAttribute(\"type\",\"text/css\"),m.styleSheet.cssText=u):m.innerHTML=u,w(i).addClass(\"laydate-theme-molv\"),i.appendChild(m)}e.remove(T.thisElemDate),a?t.elem.append(i):(document.body.appendChild(i),e.position()),e.checkDate().calendar(),e.changeEvent(),T.thisElemDate=e.elemID,\"function\"==typeof t.ready&&t.ready(w.extend({},t.dateTime,{month:t.dateTime.month+1}))},T.prototype.remove=function(e){var t=this,n=(t.config,w(\"#\"+(e||t.elemID)));return n.hasClass(c)||t.checkDate(function(){n.remove()}),t},T.prototype.position=function(){var e=this,t=e.config,n=e.bindElem||t.elem[0],a=n.getBoundingClientRect(),i=e.elem.offsetWidth,r=e.elem.offsetHeight,o=function(e){return e=e?\"scrollLeft\":\"scrollTop\",document.body[e]|document.documentElement[e]},s=function(e){return document.documentElement[e?\"clientWidth\":\"clientHeight\"]},l=5,d=a.left,c=a.bottom;d+i+l>s(\"width\")&&(d=s(\"width\")-i-l),c+r+l>s()&&(c=a.top>r?a.top-r:s()-r,c-=2*l),t.position&&(e.elem.style.position=t.position),e.elem.style.left=d+(\"fixed\"===t.position?0:o(1))+\"px\",e.elem.style.top=c+(\"fixed\"===t.position?0:o())+\"px\"},T.prototype.hint=function(e){var t=this,n=(t.config,w.elem(\"div\",{\"class\":h}));t.elem&&(n.innerHTML=e||\"\",w(t.elem).find(\".\"+h).remove(),t.elem.appendChild(n),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){w(t.elem).find(\".\"+h).remove()},3e3))},T.prototype.getAsYM=function(e,t,n){return n?t--:t++,t<0&&(t=11,e--),t>11&&(t=0,e++),[e,t]},T.prototype.systemDate=function(e){var t=e||new Date;return{year:t.getFullYear(),month:t.getMonth(),date:t.getDate(),hours:e?e.getHours():0,minutes:e?e.getMinutes():0,seconds:e?e.getSeconds():0}},T.prototype.checkDate=function(e){var t,a,i=this,r=(new Date,i.config),o=r.dateTime=r.dateTime||i.systemDate(),s=i.bindElem||r.elem[0],l=(i.isInput(s)?\"val\":\"html\",i.isInput(s)?s.value:\"static\"===r.position?\"\":s.innerHTML),c=function(e){e.year>d[1]&&(e.year=d[1],a=!0),e.month>11&&(e.month=11,a=!0),e.hours>23&&(e.hours=0,a=!0),e.minutes>59&&(e.minutes=0,e.hours++,a=!0),e.seconds>59&&(e.seconds=0,e.minutes++,a=!0),t=n.getEndDate(e.month+1,e.year),e.date>t&&(e.date=t,a=!0)},m=function(e,t,n){var o=[\"startTime\",\"endTime\"];t=(t.match(i.EXP_SPLIT)||[]).slice(1),n=n||0,r.range&&(i[o[n]]=i[o[n]]||{}),w.each(i.format,function(s,l){var c=parseFloat(t[s]);t[s].length<l.length&&(a=!0),/yyyy|y/.test(l)?(c<d[0]&&(c=d[0],a=!0),e.year=c):/MM|M/.test(l)?(c<1&&(c=1,a=!0),e.month=c-1):/dd|d/.test(l)?(c<1&&(c=1,a=!0),e.date=c):/HH|H/.test(l)?(c<1&&(c=0,a=!0),e.hours=c,r.range&&(i[o[n]].hours=c)):/mm|m/.test(l)?(c<1&&(c=0,a=!0),e.minutes=c,r.range&&(i[o[n]].minutes=c)):/ss|s/.test(l)&&(c<1&&(c=0,a=!0),e.seconds=c,r.range&&(i[o[n]].seconds=c))}),c(e)};return\"limit\"===e?(c(o),i):(l=l||r.value,\"string\"==typeof l&&(l=l.replace(/\\s+/g,\" \").replace(/^\\s|\\s$/g,\"\")),i.startState&&!i.endState&&(delete i.startState,i.endState=!0),\"string\"==typeof l&&l?i.EXP_IF.test(l)?r.range?(l=l.split(\" \"+r.range+\" \"),i.startDate=i.startDate||i.systemDate(),i.endDate=i.endDate||i.systemDate(),r.dateTime=w.extend({},i.startDate),w.each([i.startDate,i.endDate],function(e,t){m(t,l[e],e)})):m(o,l):(i.hint(\"日期格式不合法<br>必须遵循下述格式：<br>\"+(r.range?r.format+\" \"+r.range+\" \"+r.format:r.format)+\"<br>已为你重置\"),a=!0):l&&l.constructor===Date?r.dateTime=i.systemDate(l):(r.dateTime=i.systemDate(),delete i.startState,delete i.endState,delete i.startDate,delete i.endDate,delete i.startTime,delete i.endTime),c(o),a&&l&&i.setValue(r.range?i.endDate?i.parse():\"\":i.parse()),e&&e(),i)},T.prototype.mark=function(e,t){var n,a=this,i=a.config;return w.each(i.mark,function(e,a){var i=e.split(\"-\");i[0]!=t[0]&&0!=i[0]||i[1]!=t[1]&&0!=i[1]||i[2]!=t[2]||(n=a||t[2])}),n&&e.html('<span class=\"laydate-day-mark\">'+n+\"</span>\"),a},T.prototype.limit=function(e,t,n,a){var i,r=this,o=r.config,l={},d=o[n>41?\"endDate\":\"dateTime\"],c=w.extend({},d,t||{});return w.each({now:c,min:o.min,max:o.max},function(e,t){l[e]=r.newDate(w.extend({year:t.year,month:t.month,date:t.date},function(){var e={};return w.each(a,function(n,a){e[a]=t[a]}),e}())).getTime()}),i=l.now<l.min||l.now>l.max,e&&e[i?\"addClass\":\"removeClass\"](s),i},T.prototype.calendar=function(e){var t,a,i,r=this,s=r.config,l=e||s.dateTime,c=new Date,m=r.lang(),u=\"date\"!==s.type&&\"datetime\"!==s.type,h=e?1:0,y=w(r.table[h]).find(\"td\"),f=w(r.elemHeader[h][2]).find(\"span\");if(l.year<d[0]&&(l.year=d[0],r.hint(\"最低只能支持到公元\"+d[0]+\"年\")),l.year>d[1]&&(l.year=d[1],r.hint(\"最高只能支持到公元\"+d[1]+\"年\")),r.firstDate||(r.firstDate=w.extend({},l)),c.setFullYear(l.year,l.month,1),t=c.getDay(),a=n.getEndDate(l.month||12,l.year),i=n.getEndDate(l.month+1,l.year),w.each(y,function(e,n){var d=[l.year,l.month],c=0;n=w(n),n.removeAttr(\"class\"),e<t?(c=a-t+e,n.addClass(\"laydate-day-prev\"),d=r.getAsYM(l.year,l.month,\"sub\")):e>=t&&e<i+t?(c=e-t,s.range||c+1===l.date&&n.addClass(o)):(c=e-i-t,n.addClass(\"laydate-day-next\"),d=r.getAsYM(l.year,l.month)),d[1]++,d[2]=c+1,n.attr(\"lay-ymd\",d.join(\"-\")).html(d[2]),r.mark(n,d).limit(n,{year:d[0],month:d[1]-1,date:d[2]},e)}),w(f[0]).attr(\"lay-ym\",l.year+\"-\"+(l.month+1)),w(f[1]).attr(\"lay-ym\",l.year+\"-\"+(l.month+1)),\"cn\"===s.lang?(w(f[0]).attr(\"lay-type\",\"year\").html(l.year+\"年\"),w(f[1]).attr(\"lay-type\",\"month\").html(l.month+1+\"月\")):(w(f[0]).attr(\"lay-type\",\"month\").html(m.month[l.month]),w(f[1]).attr(\"lay-type\",\"year\").html(l.year)),u&&(s.range&&(e?r.endDate=r.endDate||{year:l.year+(\"year\"===s.type?1:0),month:l.month+(\"month\"===s.type?0:-1)}:r.startDate=r.startDate||{year:l.year,month:l.month},e&&(r.listYM=[[r.startDate.year,r.startDate.month+1],[r.endDate.year,r.endDate.month+1]],r.list(s.type,0).list(s.type,1),\"time\"===s.type?r.setBtnStatus(\"时间\",w.extend({},r.systemDate(),r.startTime),w.extend({},r.systemDate(),r.endTime)):r.setBtnStatus(!0))),s.range||(r.listYM=[[l.year,l.month+1]],r.list(s.type,0))),s.range&&!e){var p=r.getAsYM(l.year,l.month);r.calendar(w.extend({},l,{year:p[0],month:p[1]}))}return s.range||r.limit(w(r.footer).find(g),null,0,[\"hours\",\"minutes\",\"seconds\"]),s.range&&e&&!u&&r.stampRange(),r},T.prototype.list=function(e,t){var n=this,a=n.config,i=a.dateTime,r=n.lang(),l=a.range&&\"date\"!==a.type&&\"datetime\"!==a.type,d=w.elem(\"ul\",{\"class\":m+\" \"+{year:\"laydate-year-list\",month:\"laydate-month-list\",time:\"laydate-time-list\"}[e]}),c=n.elemHeader[t],u=w(c[2]).find(\"span\"),h=n.elemCont[t||0],y=w(h).find(\".\"+m)[0],f=\"cn\"===a.lang,p=f?\"年\":\"\",T=n.listYM[t]||{},C=[\"hours\",\"minutes\",\"seconds\"],x=[\"startTime\",\"endTime\"][t];if(T[0]<1&&(T[0]=1),\"year\"===e){var M,b=M=T[0]-7;b<1&&(b=M=1),w.each(new Array(15),function(e){var i=w.elem(\"li\",{\"lay-ym\":M}),r={year:M};M==T[0]&&w(i).addClass(o),i.innerHTML=M+p,d.appendChild(i),M<n.firstDate.year?(r.month=a.min.month,r.date=a.min.date):M>=n.firstDate.year&&(r.month=a.max.month,r.date=a.max.date),n.limit(w(i),r,t),M++}),w(u[f?0:1]).attr(\"lay-ym\",M-8+\"-\"+T[1]).html(b+p+\" - \"+(M-1+p))}else if(\"month\"===e)w.each(new Array(12),function(e){var i=w.elem(\"li\",{\"lay-ym\":e}),s={year:T[0],month:e};e+1==T[1]&&w(i).addClass(o),i.innerHTML=r.month[e]+(f?\"月\":\"\"),d.appendChild(i),T[0]<n.firstDate.year?s.date=a.min.date:T[0]>=n.firstDate.year&&(s.date=a.max.date),n.limit(w(i),s,t)}),w(u[f?0:1]).attr(\"lay-ym\",T[0]+\"-\"+T[1]).html(T[0]+p);else if(\"time\"===e){var E=function(){w(d).find(\"ol\").each(function(e,a){w(a).find(\"li\").each(function(a,i){n.limit(w(i),[{hours:a},{hours:n[x].hours,minutes:a},{hours:n[x].hours,minutes:n[x].minutes,seconds:a}][e],t,[[\"hours\"],[\"hours\",\"minutes\"],[\"hours\",\"minutes\",\"seconds\"]][e])})}),a.range||n.limit(w(n.footer).find(g),n[x],0,[\"hours\",\"minutes\",\"seconds\"])};a.range?n[x]||(n[x]={hours:0,minutes:0,seconds:0}):n[x]=i,w.each([24,60,60],function(e,t){var a=w.elem(\"li\"),i=[\"<p>\"+r.time[e]+\"</p><ol>\"];w.each(new Array(t),function(t){i.push(\"<li\"+(n[x][C[e]]===t?' class=\"'+o+'\"':\"\")+\">\"+w.digit(t,2)+\"</li>\")}),a.innerHTML=i.join(\"\")+\"</ol>\",d.appendChild(a)}),E()}if(y&&h.removeChild(y),h.appendChild(d),\"year\"===e||\"month\"===e)w(n.elemMain[t]).addClass(\"laydate-ym-show\"),w(d).find(\"li\").on(\"click\",function(){var r=0|w(this).attr(\"lay-ym\");if(!w(this).hasClass(s)){if(0===t)i[e]=r,l&&(n.startDate[e]=r),n.limit(w(n.footer).find(g),null,0);else if(l)n.endDate[e]=r;else{var c=\"year\"===e?n.getAsYM(r,T[1]-1,\"sub\"):n.getAsYM(T[0],r,\"sub\");w.extend(i,{year:c[0],month:c[1]})}\"year\"===a.type||\"month\"===a.type?(w(d).find(\".\"+o).removeClass(o),w(this).addClass(o),\"month\"===a.type&&\"year\"===e&&(n.listYM[t][0]=r,l&&(n[[\"startDate\",\"endDate\"][t]].year=r),n.list(\"month\",t))):(n.checkDate(\"limit\").calendar(),n.closeList()),n.setBtnStatus(),a.range||n.done(null,\"change\"),w(n.footer).find(D).removeClass(s)}});else{var S=w.elem(\"span\",{\"class\":v}),k=function(){w(d).find(\"ol\").each(function(e){var t=this,a=w(t).find(\"li\");t.scrollTop=30*(n[x][C[e]]-2),t.scrollTop<=0&&a.each(function(e,n){if(!w(this).hasClass(s))return t.scrollTop=30*(e-2),!0})})},H=w(c[2]).find(\".\"+v);k(),S.innerHTML=a.range?[r.startTime,r.endTime][t]:r.timeTips,w(n.elemMain[t]).addClass(\"laydate-time-show\"),H[0]&&H.remove(),c[2].appendChild(S),w(d).find(\"ol\").each(function(e){var t=this;w(t).find(\"li\").on(\"click\",function(){var r=0|this.innerHTML;w(this).hasClass(s)||(a.range?n[x][C[e]]=r:i[C[e]]=r,w(t).find(\".\"+o).removeClass(o),w(this).addClass(o),E(),k(),(n.endDate||\"time\"===a.type)&&n.done(null,\"change\"),n.setBtnStatus())})})}return n},T.prototype.listYM=[],T.prototype.closeList=function(){var e=this;e.config;w.each(e.elemCont,function(t,n){w(this).find(\".\"+m).remove(),w(e.elemMain[t]).removeClass(\"laydate-ym-show laydate-time-show\")}),w(e.elem).find(\".\"+v).remove()},T.prototype.setBtnStatus=function(e,t,n){var a,i=this,r=i.config,o=w(i.footer).find(g),d=r.range&&\"date\"!==r.type&&\"time\"!==r.type;d&&(t=t||i.startDate,n=n||i.endDate,a=i.newDate(t).getTime()>i.newDate(n).getTime(),i.limit(null,t)||i.limit(null,n)?o.addClass(s):o[a?\"addClass\":\"removeClass\"](s),e&&a&&i.hint(\"string\"==typeof e?l.replace(/日期/g,e):l))},T.prototype.parse=function(e,t){var n=this,a=n.config,i=t||(e?w.extend({},n.endDate,n.endTime):a.range?w.extend({},n.startDate,n.startTime):a.dateTime),r=n.format.concat();return w.each(r,function(e,t){/yyyy|y/.test(t)?r[e]=w.digit(i.year,t.length):/MM|M/.test(t)?r[e]=w.digit(i.month+1,t.length):/dd|d/.test(t)?r[e]=w.digit(i.date,t.length):/HH|H/.test(t)?r[e]=w.digit(i.hours,t.length):/mm|m/.test(t)?r[e]=w.digit(i.minutes,t.length):/ss|s/.test(t)&&(r[e]=w.digit(i.seconds,t.length))}),a.range&&!e?r.join(\"\")+\" \"+a.range+\" \"+n.parse(1):r.join(\"\")},T.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},T.prototype.setValue=function(e){var t=this,n=t.config,a=t.bindElem||n.elem[0],i=t.isInput(a)?\"val\":\"html\";return\"static\"===n.position||w(a)[i](e||\"\"),this},T.prototype.stampRange=function(){var e,t,n=this,a=n.config,i=w(n.elem).find(\"td\");if(a.range&&!n.endDate&&w(n.footer).find(g).addClass(s),n.endDate)return e=n.newDate({year:n.startDate.year,month:n.startDate.month,date:n.startDate.date}).getTime(),t=n.newDate({year:n.endDate.year,month:n.endDate.month,date:n.endDate.date}).getTime(),e>t?n.hint(l):void w.each(i,function(a,i){var r=w(i).attr(\"lay-ymd\").split(\"-\"),s=n.newDate({year:r[0],month:r[1]-1,date:r[2]}).getTime();w(i).removeClass(u+\" \"+o),s!==e&&s!==t||w(i).addClass(w(i).hasClass(y)||w(i).hasClass(f)?u:o),s>e&&s<t&&w(i).addClass(u)})},T.prototype.done=function(e,t){var n=this,a=n.config,i=w.extend({},n.startDate?w.extend(n.startDate,n.startTime):a.dateTime),r=w.extend({},w.extend(n.endDate,n.endTime));return w.each([i,r],function(e,t){\"month\"in t&&w.extend(t,{month:t.month+1})}),e=e||[n.parse(),i,r],\"function\"==typeof a[t||\"done\"]&&a[t||\"done\"].apply(a,e),n},T.prototype.choose=function(e){var t=this,n=t.config,a=n.dateTime,i=w(t.elem).find(\"td\"),r=e.attr(\"lay-ymd\").split(\"-\"),l=function(e){new Date;e&&w.extend(a,r),n.range&&(t.startDate?w.extend(t.startDate,r):t.startDate=w.extend({},r,t.startTime),t.startYMD=r)};if(r={year:0|r[0],month:(0|r[1])-1,date:0|r[2]},!e.hasClass(s))if(n.range){if(w.each([\"startTime\",\"endTime\"],function(e,n){t[n]=t[n]||{hours:0,minutes:0,seconds:0}}),t.endState)l(),delete t.endState,delete t.endDate,t.startState=!0,i.removeClass(o+\" \"+u),e.addClass(o);else if(t.startState){if(e.addClass(o),t.endDate?w.extend(t.endDate,r):t.endDate=w.extend({},r,t.endTime),t.newDate(r).getTime()<t.newDate(t.startYMD).getTime()){var d=w.extend({},t.endDate,{hours:t.startDate.hours,minutes:t.startDate.minutes,seconds:t.startDate.seconds});w.extend(t.endDate,t.startDate,{hours:t.endDate.hours,minutes:t.endDate.minutes,seconds:t.endDate.seconds}),t.startDate=d}n.showBottom||t.done(),t.stampRange(),t.endState=!0,t.done(null,\"change\")}else e.addClass(o),l(),t.startState=!0;w(t.footer).find(g)[t.endDate?\"removeClass\":\"addClass\"](s)}else\"static\"===n.position?(l(!0),t.calendar().done().done(null,\"change\")):\"date\"===n.type?(l(!0),t.setValue(t.parse()).remove().done()):\"datetime\"===n.type&&(l(!0),t.calendar().done(null,\"change\"))},T.prototype.tool=function(e,t){var n=this,a=n.config,i=a.dateTime,r=\"static\"===a.position,o={datetime:function(){w(e).hasClass(s)||(n.list(\"time\",0),a.range&&n.list(\"time\",1),w(e).attr(\"lay-type\",\"date\").html(n.lang().dateTips))},date:function(){n.closeList(),w(e).attr(\"lay-type\",\"datetime\").html(n.lang().timeTips)},clear:function(){n.setValue(\"\").remove(),r&&(w.extend(i,n.firstDate),n.calendar()),a.range&&(delete n.startState,delete n.endState,delete n.endDate,delete n.startTime,delete n.endTime),n.done([\"\",{},{}])},now:function(){var e=new Date;w.extend(i,n.systemDate(),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()}),n.setValue(n.parse()).remove(),r&&n.calendar(),n.done()},confirm:function(){if(a.range){if(!n.endDate)return n.hint(\"请先选择日期范围\");if(w(e).hasClass(s))return n.hint(\"time\"===a.type?l.replace(/日期/g,\"时间\"):l)}else if(w(e).hasClass(s))return n.hint(\"不在有效日期或时间范围内\");n.done(),n.setValue(n.parse()).remove()}};o[t]&&o[t]()},T.prototype.change=function(e){var t=this,n=t.config,a=n.dateTime,i=n.range&&(\"year\"===n.type||\"month\"===n.type),r=t.elemCont[e||0],o=t.listYM[e],s=function(s){var l=[\"startDate\",\"endDate\"][e],d=w(r).find(\".laydate-year-list\")[0],c=w(r).find(\".laydate-month-list\")[0];return d&&(o[0]=s?o[0]-15:o[0]+15,t.list(\"year\",e)),c&&(s?o[0]--:o[0]++,t.list(\"month\",e)),(d||c)&&(w.extend(a,{year:o[0]}),i&&(t[l].year=o[0]),n.range||t.done(null,\"change\"),t.setBtnStatus(),n.range||t.limit(w(t.footer).find(g),{year:o[0]})),d||c};return{prevYear:function(){s(\"sub\")||(a.year--,t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\"))},prevMonth:function(){var e=t.getAsYM(a.year,a.month,\"sub\");w.extend(a,{year:e[0],month:e[1]}),t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\")},nextMonth:function(){var e=t.getAsYM(a.year,a.month);w.extend(a,{year:e[0],month:e[1]}),t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\")},nextYear:function(){s()||(a.year++,t.checkDate(\"limit\").calendar(),n.range||t.done(null,\"change\"))}}},T.prototype.changeEvent=function(){var e=this;e.config;w(e.elem).on(\"click\",function(e){w.stope(e)}),w.each(e.elemHeader,function(t,n){w(n[0]).on(\"click\",function(n){e.change(t).prevYear()}),w(n[1]).on(\"click\",function(n){e.change(t).prevMonth()}),w(n[2]).find(\"span\").on(\"click\",function(n){var a=w(this),i=a.attr(\"lay-ym\"),r=a.attr(\"lay-type\");i&&(i=i.split(\"-\"),e.listYM[t]=[0|i[0],0|i[1]],e.list(r,t),w(e.footer).find(D).addClass(s))}),w(n[3]).on(\"click\",function(n){e.change(t).nextMonth()}),w(n[4]).on(\"click\",function(n){e.change(t).nextYear()})}),w.each(e.table,function(t,n){var a=w(n).find(\"td\");a.on(\"click\",function(){e.choose(w(this))})}),w(e.footer).find(\"span\").on(\"click\",function(){var t=w(this).attr(\"lay-type\");e.tool(this,t)})},T.prototype.isInput=function(e){return/input|textarea/.test(e.tagName.toLocaleLowerCase())},T.prototype.events=function(){var e=this,t=e.config,n=function(n,a){n.on(t.trigger,function(){a&&(e.bindElem=this),e.render()})};t.elem[0]&&!t.elem[0].eventHandler&&(n(t.elem,\"bind\"),n(t.eventElem),w(document).on(\"click\",function(n){n.target!==t.elem[0]&&n.target!==t.eventElem[0]&&n.target!==w(t.closeStop)[0]&&e.remove()}).on(\"keydown\",function(t){13===t.keyCode&&w(\"#\"+e.elemID)[0]&&e.elemID===T.thisElem&&(t.preventDefault(),w(e.footer).find(g)[0].click())}),w(window).on(\"resize\",function(){return!(!e.elem||!w(r)[0])&&void e.position()}),t.elem[0].eventHandler=!0)},n.render=function(e){var t=new T(e);return a.call(t)},n.getEndDate=function(e,t){var n=new Date;return n.setFullYear(t||n.getFullYear(),e||n.getMonth()+1,1),new Date(n.getTime()-864e5).getDate()},window.lay=window.lay||w,e?(n.ready(),layui.define(function(e){n.path=layui.cache.dir,e(i,n)})):\"function\"==typeof define&&define.amd?define(function(){return n}):function(){n.ready(),window.laydate=n}()}();!function(e,t){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(e,t){function n(e){var t=!!e&&\"length\"in e&&e.length,n=pe.type(e);return\"function\"!==n&&!pe.isWindow(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&t>0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if(\"string\"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener(\"DOMContentLoaded\",s),e.removeEventListener(\"load\",s)):(re.detachEvent(\"onreadystatechange\",s),e.detachEvent(\"onload\",s))}function s(){(re.addEventListener||\"load\"===e.event.type||\"complete\"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r=\"data-\"+t.replace(_e,\"-$1\").toLowerCase();if(n=e.getAttribute(r),\"string\"==typeof n){try{n=\"true\"===n||\"false\"!==n&&(\"null\"===n?null:+n+\"\"===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if((\"data\"!==t||!pe.isEmptyObject(e[t]))&&\"toJSON\"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||\"string\"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),\"object\"!=typeof t&&\"function\"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),\"string\"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(\" \")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,\"\")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?\"\":\"px\"),c=(pe.cssNumber[t]||\"px\"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||\".5\",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}function p(e){var t=ze.split(\"|\"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,\"globalEval\",!t||pe._data(t[r],\"globalEval\"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x<d;x++)if(a=e[x],a||0===a)if(\"object\"===pe.type(a))pe.merge(v,a.nodeType?[a]:a);else if(Ue.test(a)){for(u=u||y.appendChild(t.createElement(\"div\")),l=(We.exec(a)||[\"\",\"\"])[1].toLowerCase(),f=Xe[l]||Xe._default,u.innerHTML=f[1]+pe.htmlPrefilter(a)+f[2],o=f[0];o--;)u=u.lastChild;if(!fe.leadingWhitespace&&$e.test(a)&&v.push(t.createTextNode($e.exec(a)[0])),!fe.tbody)for(a=\"table\"!==l||Ve.test(a)?\"<table>\"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],\"tbody\")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent=\"\";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,\"input\"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),\"script\"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||\"\")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){\"string\"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,\"table\")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,\"tr\")?e.getElementsByTagName(\"tbody\")[0]||e.appendChild(e.ownerDocument.createElement(\"tbody\")):e}function C(e){return e.type=(null!==pe.find.attr(e,\"type\"))+\"/\"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute(\"type\"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r<i;r++)pe.event.add(t,n,s[n][r])}a.data&&(a.data=pe.extend({},a.data))}}function k(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!fe.noCloneEvent&&t[pe.expando]){i=pe._data(t);for(r in i.events)pe.removeEvent(t,r,i.handle);t.removeAttribute(pe.expando)}\"script\"===n&&t.text!==e.text?(C(t).text=e.text,E(t)):\"object\"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),fe.html5Clone&&e.innerHTML&&!pe.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):\"input\"===n&&Be.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):\"option\"===n?t.defaultSelected=t.selected=e.defaultSelected:\"input\"!==n&&\"textarea\"!==n||(t.defaultValue=e.defaultValue)}}function S(e,t,n,r){t=oe.apply([],t);var i,o,a,s,u,l,c=0,f=e.length,d=f-1,p=t[0],g=pe.isFunction(p);if(g||f>1&&\"string\"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,\"script\"),C),a=s.length;c<f;c++)o=l,c!==d&&(o=pe.clone(o,!0,!0),a&&pe.merge(s,h(o,\"script\"))),n.call(e[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,pe.map(s,E),c=0;c<a;c++)o=s[c],Ie.test(o.type||\"\")&&!pe._data(o,\"globalEval\")&&pe.contains(u,o)&&(o.src?pe._evalUrl&&pe._evalUrl(o.src):pe.globalEval((o.text||o.textContent||o.innerHTML||\"\").replace(ot,\"\")));l=i=null}return e}function A(e,t,n){for(var r,i=t?pe.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||pe.cleanData(h(r)),r.parentNode&&(n&&pe.contains(r.ownerDocument,r)&&g(h(r,\"script\")),r.parentNode.removeChild(r));return e}function D(e,t){var n=pe(t.createElement(e)).appendTo(t.body),r=pe.css(n[0],\"display\");return n.detach(),r}function j(e){var t=re,n=lt[e];return n||(n=D(e,t),\"none\"!==n&&n||(ut=(ut||pe(\"<iframe frameborder='0' width='0' height='0'/>\")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a<s;a++)r=e[a],r.style&&(o[a]=pe._data(r,\"olddisplay\"),n=r.style.display,t?(o[a]||\"none\"!==n||(r.style.display=\"\"),\"\"===r.style.display&&Re(r)&&(o[a]=pe._data(r,\"olddisplay\",j(r.nodeName)))):(i=Re(r),(n&&\"none\"!==n||!i)&&pe._data(r,\"olddisplay\",i?n:pe.css(r,\"display\"))));for(a=0;a<s;a++)r=e[a],r.style&&(t&&\"none\"!==r.style.display&&\"\"!==r.style.display||(r.style.display=t?o[a]||\"\":\"none\"));return e}function _(e,t,n){var r=bt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||\"px\"):t}function F(e,t,n,r,i){for(var o=n===(r?\"border\":\"content\")?4:\"width\"===t?1:0,a=0;o<4;o+=2)\"margin\"===n&&(a+=pe.css(e,n+Oe[o],!0,i)),r?(\"content\"===n&&(a-=pe.css(e,\"padding\"+Oe[o],!0,i)),\"margin\"!==n&&(a-=pe.css(e,\"border\"+Oe[o]+\"Width\",!0,i))):(a+=pe.css(e,\"padding\"+Oe[o],!0,i),\"padding\"!==n&&(a+=pe.css(e,\"border\"+Oe[o]+\"Width\",!0,i)));return a}function M(t,n,r){var i=!0,o=\"width\"===n?t.offsetWidth:t.offsetHeight,a=ht(t),s=fe.boxSizing&&\"border-box\"===pe.css(t,\"boxSizing\",!1,a);if(re.msFullscreenElement&&e.top!==e&&t.getClientRects().length&&(o=Math.round(100*t.getBoundingClientRect()[n])),o<=0||null==o){if(o=gt(t,n,a),(o<0||null==o)&&(o=t.style[n]),ft.test(o))return o;i=s&&(fe.boxSizingReliable()||o===t.style[n]),o=parseFloat(o)||0}return o+F(t,n,r||(s?\"border\":\"content\"),i,a)+\"px\"}function O(e,t,n,r,i){return new O.prototype.init(e,t,n,r,i)}function R(){return e.setTimeout(function(){Nt=void 0}),Nt=pe.now()}function P(e,t){var n,r={height:e},i=0;for(t=t?1:0;i<4;i+=2-t)n=Oe[i],r[\"margin\"+n]=r[\"padding\"+n]=e;return t&&(r.opacity=r.width=e),r}function B(e,t,n){for(var r,i=($.tweeners[t]||[]).concat($.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function W(e,t,n){var r,i,o,a,s,u,l,c,f=this,d={},p=e.style,h=e.nodeType&&Re(e),g=pe._data(e,\"fxshow\");n.queue||(s=pe._queueHooks(e,\"fx\"),null==s.unqueued&&(s.unqueued=0,u=s.empty.fire,s.empty.fire=function(){s.unqueued||u()}),s.unqueued++,f.always(function(){f.always(function(){s.unqueued--,pe.queue(e,\"fx\").length||s.empty.fire()})})),1===e.nodeType&&(\"height\"in t||\"width\"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],l=pe.css(e,\"display\"),c=\"none\"===l?pe._data(e,\"olddisplay\")||j(e.nodeName):l,\"inline\"===c&&\"none\"===pe.css(e,\"float\")&&(fe.inlineBlockNeedsLayout&&\"inline\"!==j(e.nodeName)?p.zoom=1:p.display=\"inline-block\")),n.overflow&&(p.overflow=\"hidden\",fe.shrinkWrapBlocks()||f.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],St.exec(i)){if(delete t[r],o=o||\"toggle\"===i,i===(h?\"hide\":\"show\")){if(\"show\"!==i||!g||void 0===g[r])continue;h=!0}d[r]=g&&g[r]||pe.style(e,r)}else l=void 0;if(pe.isEmptyObject(d))\"inline\"===(\"none\"===l?j(e.nodeName):l)&&(p.display=l);else{g?\"hidden\"in g&&(h=g.hidden):g=pe._data(e,\"fxshow\",{}),o&&(g.hidden=!h),h?pe(e).show():f.done(function(){pe(e).hide()}),f.done(function(){var t;pe._removeData(e,\"fxshow\");for(t in d)pe.style(e,t,d[t])});for(r in d)a=B(h?g[r]:0,r,f),r in g||(g[r]=a.start,h&&(a.end=a.start,a.start=\"width\"===r||\"height\"===r?1:0))}}function I(e,t){var n,r,i,o,a;for(n in e)if(r=pe.camelCase(n),i=t[r],o=e[n],pe.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=pe.cssHooks[r],a&&\"expand\"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function $(e,t,n){var r,i,o=0,a=$.prefilters.length,s=pe.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=Nt||R(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;a<u;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),o<1&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:pe.extend({},t),opts:pe.extend(!0,{specialEasing:{},easing:pe.easing._default},n),originalProperties:t,originalOptions:n,startTime:Nt||R(),duration:n.duration,tweens:[],createTween:function(t,n){var r=pe.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?(s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l,t])):s.rejectWith(e,[l,t]),this}}),c=l.props;for(I(c,l.opts.specialEasing);o<a;o++)if(r=$.prefilters[o].call(l,e,c,l.opts))return pe.isFunction(r.stop)&&(pe._queueHooks(l.elem,l.opts.queue).stop=pe.proxy(r.stop,r)),r;return pe.map(c,B,l),pe.isFunction(l.opts.start)&&l.opts.start.call(e,l),pe.fx.timer(pe.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function z(e){return pe.attr(e,\"class\")||\"\"}function X(e){return function(t,n){\"string\"!=typeof t&&(n=t,t=\"*\");var r,i=0,o=t.toLowerCase().match(De)||[];if(pe.isFunction(n))for(;r=o[i++];)\"+\"===r.charAt(0)?(r=r.slice(1)||\"*\",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function U(e,t,n,r){function i(s){var u;return o[s]=!0,pe.each(e[s]||[],function(e,s){var l=s(t,n,r);return\"string\"!=typeof l||a||o[l]?a?!(u=l):void 0:(t.dataTypes.unshift(l),i(l),!1)}),u}var o={},a=e===Qt;return i(t.dataTypes[0])||!o[\"*\"]&&i(\"*\")}function V(e,t){var n,r,i=pe.ajaxSettings.flatOptions||{};for(r in t)void 0!==t[r]&&((i[r]?e:n||(n={}))[r]=t[r]);return n&&pe.extend(!0,e,n),e}function Y(e,t,n){for(var r,i,o,a,s=e.contents,u=e.dataTypes;\"*\"===u[0];)u.shift(),void 0===i&&(i=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(i)for(a in s)if(s[a]&&s[a].test(i)){u.unshift(a);break}if(u[0]in n)o=u[0];else{for(a in n){if(!u[0]||e.converters[a+\" \"+u[0]]){o=a;break}r||(r=a)}o=o||r}if(o)return o!==u[0]&&u.unshift(o),n[o]}function J(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(a=l[u+\" \"+o]||l[\"* \"+o],!a)for(i in l)if(s=i.split(\" \"),s[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){a===!0?a=l[i]:l[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(f){return{state:\"parsererror\",error:a?f:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}function G(e){return e.style&&e.style.display||pe.css(e,\"display\")}function K(e){for(;e&&1===e.nodeType;){if(\"none\"===G(e)||\"hidden\"===e.type)return!0;e=e.parentNode}return!1}function Q(e,t,n,r){var i;if(pe.isArray(t))pe.each(t,function(t,i){n||rn.test(e)?r(e,i):Q(e+\"[\"+(\"object\"==typeof i&&null!=i?t:\"\")+\"]\",i,n,r)});else if(n||\"object\"!==pe.type(t))r(e,t);else for(i in t)Q(e+\"[\"+i+\"]\",t[i],n,r)}function Z(){try{return new e.XMLHttpRequest}catch(t){}}function ee(){try{return new e.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(t){}}function te(e){return pe.isWindow(e)?e:9===e.nodeType&&(e.defaultView||e.parentWindow)}var ne=[],re=e.document,ie=ne.slice,oe=ne.concat,ae=ne.push,se=ne.indexOf,ue={},le=ue.toString,ce=ue.hasOwnProperty,fe={},de=\"1.12.3\",pe=function(e,t){return new pe.fn.init(e,t)},he=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,ge=/^-ms-/,me=/-([\\da-z])/gi,ye=function(e,t){return t.toUpperCase()};pe.fn=pe.prototype={jquery:de,constructor:pe,selector:\"\",length:0,toArray:function(){return ie.call(this)},get:function(e){return null!=e?e<0?this[e+this.length]:this[e]:ie.call(this)},pushStack:function(e){var t=pe.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e){return pe.each(this,e)},map:function(e){return this.pushStack(pe.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(ie.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:ae,sort:ne.sort,splice:ne.splice},pe.extend=pe.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||pe.isFunction(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(i=arguments[s]))for(r in i)e=a[r],n=i[r],a!==n&&(l&&n&&(pe.isPlainObject(n)||(t=pe.isArray(n)))?(t?(t=!1,o=e&&pe.isArray(e)?e:[]):o=e&&pe.isPlainObject(e)?e:{},a[r]=pe.extend(l,o,n)):void 0!==n&&(a[r]=n));return a},pe.extend({expando:\"jQuery\"+(de+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isFunction:function(e){return\"function\"===pe.type(e)},isArray:Array.isArray||function(e){return\"array\"===pe.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){var t=e&&e.toString();return!pe.isArray(e)&&t-parseFloat(t)+1>=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||\"object\"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,\"constructor\")&&!ce.call(e.constructor.prototype,\"isPrototypeOf\"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?ue[le.call(e)]||\"object\":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,\"ms-\").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;i<r&&t.call(e[i],i,e[i])!==!1;i++);else for(i in e)if(t.call(e[i],i,e[i])===!1)break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(he,\"\")},makeArray:function(e,t){var r=t||[];return null!=e&&(n(Object(e))?pe.merge(r,\"string\"==typeof e?[e]:e):ae.call(r,e)),r},inArray:function(e,t,n){var r;if(t){if(se)return se.call(t,e,n);for(r=t.length,n=n?n<0?Math.max(0,r+n):n:0;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;)e[i++]=t[r++];if(n!==n)for(;void 0!==t[r];)e[i++]=t[r++];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)r=!t(e[o],o),r!==s&&i.push(e[o]);return i},map:function(e,t,r){var i,o,a=0,s=[];if(n(e))for(i=e.length;a<i;a++)o=t(e[a],a,r),null!=o&&s.push(o);else for(a in e)o=t(e[a],a,r),null!=o&&s.push(o);return oe.apply([],s)},guid:1,proxy:function(e,t){var n,r,i;if(\"string\"==typeof t&&(i=e[t],t=e,e=i),pe.isFunction(e))return n=ie.call(arguments,2),r=function(){return e.apply(t||this,n.concat(ie.call(arguments)))},r.guid=e.guid=e.guid||pe.guid++,r},now:function(){return+new Date},support:fe}),\"function\"==typeof Symbol&&(pe.fn[Symbol.iterator]=ne[Symbol.iterator]),pe.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){ue[\"[object \"+t+\"]\"]=t.toLowerCase()});var ve=function(e){function t(e,t,n,r){var i,o,a,s,u,l,f,p,h=t&&t.ownerDocument,g=t?t.nodeType:9;if(n=n||[],\"string\"!=typeof e||!e||1!==g&&9!==g&&11!==g)return n;if(!r&&((t?t.ownerDocument||t:B)!==H&&L(t),t=t||H,_)){if(11!==g&&(l=ye.exec(e)))if(i=l[1]){if(9===g){if(!(a=t.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(h&&(a=h.getElementById(i))&&R(t,a)&&a.id===i)return n.push(a),n}else{if(l[2])return Q.apply(n,t.getElementsByTagName(e)),n;if((i=l[3])&&w.getElementsByClassName&&t.getElementsByClassName)return Q.apply(n,t.getElementsByClassName(i)),n}if(w.qsa&&!X[e+\" \"]&&(!F||!F.test(e))){if(1!==g)h=t,p=e;else if(\"object\"!==t.nodeName.toLowerCase()){for((s=t.getAttribute(\"id\"))?s=s.replace(xe,\"\\\\$&\"):t.setAttribute(\"id\",s=P),f=N(e),o=f.length,u=de.test(s)?\"#\"+s:\"[id='\"+s+\"']\";o--;)f[o]=u+\" \"+d(f[o]);p=f.join(\",\"),h=ve.test(e)&&c(t.parentNode)||t}if(p)try{return Q.apply(n,h.querySelectorAll(p)),n}catch(m){}finally{s===P&&t.removeAttribute(\"id\")}}}return S(e.replace(se,\"$1\"),t,n,r)}function n(){function e(n,r){return t.push(n+\" \")>T.cacheLength&&delete e[t.shift()],e[n+\" \"]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement(\"div\");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split(\"|\"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return\"input\"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return(\"input\"===n||\"button\"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function p(e,t,n){var r=t.dir,i=n&&\"parentNode\"===r,o=I++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,u,l,c=[W,o];if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i){if(l=t[P]||(t[P]={}),u=l[t.uniqueID]||(l[t.uniqueID]={}),(s=u[r])&&s[0]===W&&s[1]===o)return c[2]=s[2];if(u[r]=c,c[2]=e(t,n,a))return!0}}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i<o;i++)t(e,n[i],r);return r}function m(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function y(e,t,n,i,o,a){return i&&!i[P]&&(i=y(i)),o&&!o[P]&&(o=y(o,a)),r(function(r,a,s,u){var l,c,f,d=[],p=[],h=a.length,y=r||g(t||\"*\",s.nodeType?[s]:s,[]),v=!e||!r&&t?y:m(y,d,e,s,u),x=n?o||(r?e:h||i)?[]:a:v;if(n&&n(v,x,s,u),i)for(l=m(x,p),i(l,[],s,u),c=l.length;c--;)(f=l[c])&&(x[p[c]]=!(v[p[c]]=f));if(r){if(o||e){if(o){for(l=[],c=x.length;c--;)(f=x[c])&&l.push(v[c]=f);o(null,x=[],l,u)}for(c=x.length;c--;)(f=x[c])&&(l=o?ee(r,f):d[c])>-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[\" \"],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s<i;s++)if(n=T.relative[e[s].type])c=[p(h(c),n)];else{if(n=T.filter[e[s].type].apply(null,e[s].matches),n[P]){for(r=++s;r<i&&!T.relative[e[r].type];r++);return y(s>1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(se,\"$1\"),n,s<r&&v(e.slice(s,r)),r<i&&v(e=e.slice(r)),r<i&&d(e))}c.push(n)}return h(c)}function x(e,n){var i=n.length>0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h=\"0\",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG(\"*\",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P=\"sizzle\"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},te=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",ne=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",re=\"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",ie=\"\\\\[\"+ne+\"*(\"+re+\")(?:\"+ne+\"*([*^$|!~]?=)\"+ne+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+re+\"))|)\"+ne+\"*\\\\]\",oe=\":(\"+re+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+ie+\")*)|.*)\\\\)|)\",ae=new RegExp(ne+\"+\",\"g\"),se=new RegExp(\"^\"+ne+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+ne+\"+$\",\"g\"),ue=new RegExp(\"^\"+ne+\"*,\"+ne+\"*\"),le=new RegExp(\"^\"+ne+\"*([>+~]|\"+ne+\")\"+ne+\"*\"),ce=new RegExp(\"=\"+ne+\"*([^\\\\]'\\\"]*?)\"+ne+\"*\\\\]\",\"g\"),fe=new RegExp(oe),de=new RegExp(\"^\"+re+\"$\"),pe={ID:new RegExp(\"^#(\"+re+\")\"),CLASS:new RegExp(\"^\\\\.(\"+re+\")\"),TAG:new RegExp(\"^(\"+re+\"|[*])\"),ATTR:new RegExp(\"^\"+ie),PSEUDO:new RegExp(\"^\"+oe),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+ne+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+ne+\"*(?:([+-]|)\"+ne+\"*(\\\\d+)|))\"+ne+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+te+\")$\",\"i\"),needsContext:new RegExp(\"^\"+ne+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+ne+\"*((?:-\\\\d)?\\\\d*)\"+ne+\"*\\\\)|)(?=[^-]|$)\",\"i\")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\\d$/i,me=/^[^{]+\\{\\s*\\[native \\w/,ye=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ve=/[+~]/,xe=/'|\\\\/g,be=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+ne+\"?|(\"+ne+\")|.)\",\"ig\"),we=function(e,t,n){var r=\"0x\"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&\"HTML\"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",Te,!1):n.attachEvent&&n.attachEvent(\"onunload\",Te)),w.attributes=i(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute(\"id\")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML=\"<a id='\"+P+\"'></a><select id='\"+P+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&F.push(\"[*^$]=\"+ne+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||F.push(\"\\\\[\"+ne+\"*(?:value|\"+te+\")\"),e.querySelectorAll(\"[id~=\"+P+\"-]\").length||F.push(\"~=\"),e.querySelectorAll(\":checked\").length||F.push(\":checked\"),e.querySelectorAll(\"a#\"+P+\"+*\").length||F.push(\".#.+[+~]\")}),i(function(e){var t=H.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&F.push(\"name\"+ne+\"*[*^$|!~]?=\"),e.querySelectorAll(\":enabled\").length||F.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),F.push(\",.*:\")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,\"div\"),O.call(e,\"[s!='']:x\"),M.push(\"!=\",oe)}),F=F.length&&new RegExp(F.join(\"|\")),M=M.length&&new RegExp(M.join(\"|\")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,\"='$1']\"),w.matchesSelector&&_&&!X[n+\" \"]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,we),e[3]=(e[3]||e[4]||e[5]||\"\").replace(be,we),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&fe.test(n)&&(t=N(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(be,we).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+\" \"];return t||(t=new RegExp(\"(^|\"+ne+\")\"+e+\"(\"+ne+\"|$)\"))&&$(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?\"!=\"===n:!n||(o+=\"\",\"=\"===n?o===r:\"!=\"===n?o!==r:\"^=\"===n?r&&0===o.indexOf(r):\"*=\"===n?r&&o.indexOf(r)>-1:\"$=\"===n?r&&o.slice(-r.length)===r:\"~=\"===n?(\" \"+o.replace(ae,\" \")+\" \").indexOf(r)>-1:\"|=\"===n&&(o===r||o.slice(0,r.length+1)===r+\"-\"))}},CHILD:function(e,t,n,r,i){var o=\"nth\"!==e.slice(0,3),a=\"last\"!==e.slice(-4),s=\"of-type\"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?\"nextSibling\":\"previousSibling\",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g=\"only\"===e&&!h&&\"nextSibling\"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),\nl=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error(\"unsupported pseudo: \"+e);return o[P]?o(n):o.length>1?(i=[e,e,\"\",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,\"$1\"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||\"\")||t.error(\"unsupported lang: \"+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute(\"xml:lang\")||t.getAttribute(\"lang\"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+\"-\");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:l(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:l(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},T.pseudos.nth=T.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})T.pseudos[b]=s(b);for(b in{submit:!0,reset:!0})T.pseudos[b]=u(b);return f.prototype=T.filters=T.pseudos,T.setFilters=new f,N=t.tokenize=function(e,n){var r,i,o,a,s,u,l,c=z[e+\" \"];if(c)return n?0:c.slice(0);for(s=e,u=[],l=T.preFilter;s;){r&&!(i=ue.exec(s))||(i&&(s=s.slice(i[0].length)||s),u.push(o=[])),r=!1,(i=le.exec(s))&&(r=i.shift(),o.push({value:r,type:i[0].replace(se,\" \")}),s=s.slice(r.length));for(a in T.filter)!(i=pe[a].exec(s))||l[a]&&!(i=l[a](i))||(r=i.shift(),o.push({value:r,type:a,matches:i}),s=s.slice(r.length));if(!r)break}return n?s.length:s?t.error(e):z(e,u).slice(0)},k=t.compile=function(e,t){var n,r=[],i=[],o=X[e+\" \"];if(!o){for(t||(t=N(e)),n=t.length;n--;)o=v(t[n]),o[P]?r.push(o):i.push(o);o=X(e,x(i,r)),o.selector=e}return o},S=t.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,f=!r&&N(e=l.selector||e);if(n=n||[],1===f.length){if(o=f[0]=f[0].slice(0),o.length>2&&\"ID\"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split(\"\").sort(U).join(\"\")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement(\"div\"))}),i(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||o(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||o(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute(\"disabled\")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[\":\"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/,Ce=/^.[^:#\\[\\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if(\"string\"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t<i;t++)if(pe.contains(r[t],this))return!0}));for(t=0;t<i;t++)pe.find(e,r[t],n);return n=this.pushStack(i>1?pe.unique(n):n),n.selector=this.selector?this.selector+\" \"+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,\"string\"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,\"string\"==typeof e){if(r=\"<\"===e.charAt(0)&&\">\"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?\"undefined\"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(pe.contains(this,n[t]))return!0})},closest:function(e,t){for(var n,r=0,i=this.length,o=[],a=we.test(e)||\"string\"!=typeof e?pe(e,t||this.context):0;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,\"parentNode\")},parentsUntil:function(e,t,n){return xe(e,\"parentNode\",n)},next:function(e){return i(e,\"nextSibling\")},prev:function(e){return i(e,\"previousSibling\")},nextAll:function(e){return xe(e,\"nextSibling\")},prevAll:function(e){return xe(e,\"previousSibling\")},nextUntil:function(e,t,n){return xe(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return xe(e,\"previousSibling\",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,\"iframe\")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return\"Until\"!==e.slice(-5)&&(r=n),r&&\"string\"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\\S+/g;pe.Callbacks=function(e){e=\"string\"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u<a.length;)a[u].apply(n[0],n[1])===!1&&e.stopOnFalse&&(u=a.length,n=!1);e.memory||(n=!1),t=!1,i&&(a=n?[]:\"\")},c={add:function(){return a&&(n&&!t&&(u=a.length-1,s.push(n)),function r(t){pe.each(t,function(t,n){pe.isFunction(n)?e.unique&&c.has(n)||a.push(n):n&&n.length&&\"string\"!==pe.type(n)&&r(n)})}(arguments),n&&!t&&l()),this},remove:function(){return pe.each(arguments,function(e,t){for(var n;(n=pe.inArray(t,a,n))>-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n=\"\",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[[\"resolve\",\"done\",pe.Callbacks(\"once memory\"),\"resolved\"],[\"reject\",\"fail\",pe.Callbacks(\"once memory\"),\"rejected\"],[\"notify\",\"progress\",pe.Callbacks(\"memory\")]],n=\"pending\",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+\"With\"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+\"With\"](this===i?r:this,arguments),this},i[o[0]+\"With\"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i<a;i++)o[i]&&pe.isFunction(o[i].promise)?o[i].promise().progress(l(i,n,t)).done(l(i,r,o)).fail(u.reject):--s;return s||u.resolveWith(r,o),u.promise()}});var je;pe.fn.ready=function(e){return pe.ready.promise().done(e),this},pe.extend({isReady:!1,readyWait:1,holdReady:function(e){e?pe.readyWait++:pe.ready(!0)},ready:function(e){(e===!0?--pe.readyWait:pe.isReady)||(pe.isReady=!0,e!==!0&&--pe.readyWait>0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler(\"ready\"),pe(re).off(\"ready\"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),\"complete\"===re.readyState||\"loading\"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener(\"DOMContentLoaded\",s),e.addEventListener(\"load\",s);else{re.attachEvent(\"onreadystatechange\",s),e.attachEvent(\"onload\",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll(\"left\")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst=\"0\"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName(\"body\")[0],n&&n.style&&(t=re.createElement(\"div\"),r=re.createElement(\"div\"),r.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",n.appendChild(r).appendChild(t),\"undefined\"!=typeof t.style.zoom&&(t.style.cssText=\"display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1\",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement(\"div\");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+\" \").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute(\"classid\")===t)},qe=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{\"applet \":!0,\"embed \":!0,\"object \":\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,\"parsedAttrs\"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf(\"data-\")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,\"parsedAttrs\",!0)}return i}return\"object\"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks(\"once memory\").add(function(){pe._removeData(e,t+\"queue\"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return\"string\"!=typeof e&&(t=e,e=\"fx\",n--),arguments.length<n?pe.queue(this[0],e):void 0===t?this:this.each(function(){var n=pe.queue(this,e,t);pe._queueHooks(this,e),\"fx\"===e&&\"inprogress\"!==n[0]&&pe.dequeue(this,e)})},dequeue:function(e){return this.each(function(){pe.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=pe.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};for(\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";a--;)n=pe._data(o[a],e+\"queueHooks\"),n&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}}),function(){var e;fe.shrinkWrapBlocks=function(){if(null!=e)return e;e=!1;var t,n,r;return n=re.getElementsByTagName(\"body\")[0],n&&n.style?(t=re.createElement(\"div\"),r=re.createElement(\"div\"),r.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",n.appendChild(r).appendChild(t),\"undefined\"!=typeof t.style.zoom&&(t.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1\",t.appendChild(re.createElement(\"div\")).style.width=\"5px\",e=3!==t.offsetWidth),n.removeChild(r),e):void 0}}();var Fe=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,Me=new RegExp(\"^(?:([+-])=|)(\"+Fe+\")([a-z%]*)$\",\"i\"),Oe=[\"Top\",\"Right\",\"Bottom\",\"Left\"],Re=function(e,t){return e=t||e,\"none\"===pe.css(e,\"display\")||!pe.contains(e.ownerDocument,e)},Pe=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===pe.type(n)){i=!0;for(s in n)Pe(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,pe.isFunction(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(pe(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},Be=/^(?:checkbox|radio)$/i,We=/<([\\w:-]+)/,Ie=/^$|\\/(?:java|ecma)script/i,$e=/^\\s+/,ze=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video\";!function(){var e=re.createElement(\"div\"),t=re.createDocumentFragment(),n=re.createElement(\"input\");e.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName(\"tbody\").length,fe.htmlSerialize=!!e.getElementsByTagName(\"link\").length,fe.html5Clone=\"<:nav></:nav>\"!==re.createElement(\"nav\").cloneNode(!0).outerHTML,n.type=\"checkbox\",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML=\"<textarea>x</textarea>\",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement(\"input\"),n.setAttribute(\"type\",\"radio\"),n.setAttribute(\"checked\",\"checked\"),n.setAttribute(\"name\",\"t\"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],area:[1,\"<map>\",\"</map>\"],param:[1,\"<object>\",\"</object>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:fe.htmlSerialize?[0,\"\",\"\"]:[1,\"X<div>\",\"</div>\"]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|&#?\\w+;/,Ve=/<tbody/i;!function(){var t,n,r=re.createElement(\"div\");for(t in{submit:!0,change:!0,focusin:!0})n=\"on\"+t,(fe[t]=n in e)||(r.setAttribute(n,\"t\"),fe[t]=r.attributes[n].expando===!1);r=null}();var Ye=/^(?:input|select|textarea)$/i,Je=/^key/,Ge=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ke=/^(?:focusinfocus|focusoutblur)$/,Qe=/^([^.]*)(?:\\.(.+)|)/;pe.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,m=pe._data(e);if(m){for(n.handler&&(u=n,n=u.handler,i=u.selector),n.guid||(n.guid=pe.guid++),(a=m.events)||(a=m.events={}),(c=m.handle)||(c=m.handle=function(e){return\"undefined\"==typeof pe||e&&pe.event.triggered===e.type?void 0:pe.event.dispatch.apply(c.elem,arguments)},c.elem=e),t=(t||\"\").match(De)||[\"\"],s=t.length;s--;)o=Qe.exec(t[s])||[],p=g=o[1],h=(o[2]||\"\").split(\".\").sort(),p&&(l=pe.event.special[p]||{},p=(i?l.delegateType:l.bindType)||p,l=pe.event.special[p]||{},f=pe.extend({type:p,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&pe.expr.match.needsContext.test(i),namespace:h.join(\".\")},u),(d=a[p])||(d=a[p]=[],d.delegateCount=0,l.setup&&l.setup.call(e,r,h,c)!==!1||(e.addEventListener?e.addEventListener(p,c,!1):e.attachEvent&&e.attachEvent(\"on\"+p,c))),l.add&&(l.add.call(e,f),f.handler.guid||(f.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,f):d.push(f),pe.event.global[p]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,m=pe.hasData(e)&&pe._data(e);if(m&&(c=m.events)){for(t=(t||\"\").match(De)||[\"\"],l=t.length;l--;)if(s=Qe.exec(t[l])||[],p=g=s[1],h=(s[2]||\"\").split(\".\").sort(),p){for(f=pe.event.special[p]||{},p=(r?f.delegateType:f.bindType)||p,d=c[p]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),u=o=d.length;o--;)a=d[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&(\"**\"!==r||!a.selector)||(d.splice(o,1),a.selector&&d.delegateCount--,f.remove&&f.remove.call(e,a));u&&!d.length&&(f.teardown&&f.teardown.call(e,h,m.handle)!==!1||pe.removeEvent(e,p,m.handle),delete c[p])}else for(p in c)pe.event.remove(e,p+t[l],n,r,!0);pe.isEmptyObject(c)&&(delete m.handle,pe._removeData(e,\"events\"))}},trigger:function(t,n,r,i){var o,a,s,u,l,c,f,d=[r||re],p=ce.call(t,\"type\")?t.type:t,h=ce.call(t,\"namespace\")?t.namespace.split(\".\"):[];if(s=c=r=r||re,3!==r.nodeType&&8!==r.nodeType&&!Ke.test(p+pe.event.triggered)&&(p.indexOf(\".\")>-1&&(h=p.split(\".\"),p=h.shift(),h.sort()),a=p.indexOf(\":\")<0&&\"on\"+p,t=t[pe.expando]?t:new pe.Event(p,\"object\"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join(\".\"),t.rnamespace=t.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,\"events\")||{})[t.type]&&pe._data(s,\"handle\"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,\"events\")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&(\"click\"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||\"click\"!==e.type)){for(r=[],n=0;n<s;n++)o=t[n],i=o.selector+\" \",void 0===r[i]&&(r[i]=o.needsContext?pe(i,this).index(u)>-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s<t.length&&a.push({elem:this,handlers:t.slice(s)}),a},fix:function(e){if(e[pe.expando])return e;var t,n,r,i=e.type,o=e,a=this.fixHooks[i];for(a||(this.fixHooks[i]=a=Ge.test(i)?this.mouseHooks:Je.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new pe.Event(o),t=r.length;t--;)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||re),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,a.filter?a.filter(e,o):e},props:\"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(e,t){var n,r,i,o=t.button,a=t.fromElement;return null==e.pageX&&null!=t.clientX&&(r=e.target.ownerDocument||re,i=r.documentElement,n=r.body,e.pageX=t.clientX+(i&&i.scrollLeft||n&&n.scrollLeft||0)-(i&&i.clientLeft||n&&n.clientLeft||0),e.pageY=t.clientY+(i&&i.scrollTop||n&&n.scrollTop||0)-(i&&i.clientTop||n&&n.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?t.toElement:a),e.which||void 0===o||(e.which=1&o?1:2&o?3:4&o?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==b()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:\"focusin\"},blur:{trigger:function(){if(this===b()&&this.blur)return this.blur(),!1},delegateType:\"focusout\"},click:{trigger:function(){if(pe.nodeName(this,\"input\")&&\"checkbox\"===this.type&&this.click)return this.click(),!1},_default:function(e){return pe.nodeName(e.target,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n){var r=pe.extend(new pe.Event,n,{type:e,isSimulated:!0});pe.event.trigger(r,null,t),r.isDefaultPrevented()&&n.preventDefault()}},pe.removeEvent=re.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)}:function(e,t,n){var r=\"on\"+t;e.detachEvent&&(\"undefined\"==typeof e[r]&&(e[r]=null),e.detachEvent(r,n))},pe.Event=function(e,t){return this instanceof pe.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&e.returnValue===!1?v:x):this.type=e,t&&pe.extend(this,t),this.timeStamp=e&&e.timeStamp||pe.now(),void(this[pe.expando]=!0)):new pe.Event(e,t)},pe.Event.prototype={constructor:pe.Event,isDefaultPrevented:x,isPropagationStopped:x,isImmediatePropagationStopped:x,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=v,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=v,e&&!this.isSimulated&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=v,e&&e.stopImmediatePropagation&&e.stopImmediatePropagation(),this.stopPropagation()}},pe.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,t){pe.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return i&&(i===r||pe.contains(r,i))||(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),fe.submit||(pe.event.special.submit={setup:function(){return!pe.nodeName(this,\"form\")&&void pe.event.add(this,\"click._submit keypress._submit\",function(e){var t=e.target,n=pe.nodeName(t,\"input\")||pe.nodeName(t,\"button\")?pe.prop(t,\"form\"):void 0;n&&!pe._data(n,\"submit\")&&(pe.event.add(n,\"submit._submit\",function(e){e._submitBubble=!0}),pe._data(n,\"submit\",!0))})},postDispatch:function(e){e._submitBubble&&(delete e._submitBubble,this.parentNode&&!e.isTrigger&&pe.event.simulate(\"submit\",this.parentNode,e))},teardown:function(){return!pe.nodeName(this,\"form\")&&void pe.event.remove(this,\"._submit\")}}),fe.change||(pe.event.special.change={setup:function(){return Ye.test(this.nodeName)?(\"checkbox\"!==this.type&&\"radio\"!==this.type||(pe.event.add(this,\"propertychange._change\",function(e){\"checked\"===e.originalEvent.propertyName&&(this._justChanged=!0)}),pe.event.add(this,\"click._change\",function(e){this._justChanged&&!e.isTrigger&&(this._justChanged=!1),pe.event.simulate(\"change\",this,e)})),!1):void pe.event.add(this,\"beforeactivate._change\",function(e){var t=e.target;Ye.test(t.nodeName)&&!pe._data(t,\"change\")&&(pe.event.add(t,\"change._change\",function(e){!this.parentNode||e.isSimulated||e.isTrigger||pe.event.simulate(\"change\",this.parentNode,e)}),pe._data(t,\"change\",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||\"radio\"!==t.type&&\"checkbox\"!==t.type)return e.handleObj.handler.apply(this,arguments)},teardown:function(){return pe.event.remove(this,\"._change\"),!Ye.test(this.nodeName)}}),fe.focusin||pe.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){var n=function(e){pe.event.simulate(t,e.target,pe.event.fix(e))};pe.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=pe._data(r,t);i||r.addEventListener(e,n,!0),pe._data(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=pe._data(r,t)-1;i?pe._data(r,t,i):(r.removeEventListener(e,n,!0),pe._removeData(r,t))}}}),pe.fn.extend({on:function(e,t,n,r){return w(this,e,t,n,r)},one:function(e,t,n,r){return w(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,pe(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return t!==!1&&\"function\"!=typeof t||(n=t,t=void 0),n===!1&&(n=x),this.each(function(){pe.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){pe.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return pe.event.trigger(e,t,n,!0)}});var Ze=/ jQuery\\d+=\"(?:null|\\d+)\"/g,et=new RegExp(\"<(?:\"+ze+\")[\\\\s/>]\",\"i\"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,nt=/<script|<style|<link/i,rt=/checked\\s*(?:[^=]|=\\s*.checked.)/i,it=/^true\\/(.*)/,ot=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,at=p(re),st=at.appendChild(re.createElement(\"div\"));pe.extend({htmlPrefilter:function(e){return e.replace(tt,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u=pe.contains(e.ownerDocument,e);if(fe.html5Clone||pe.isXMLDoc(e)||!et.test(\"<\"+e.nodeName+\">\")?o=e.cloneNode(!0):(st.innerHTML=e.outerHTML,st.removeChild(o=st.firstChild)),!(fe.noCloneEvent&&fe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||pe.isXMLDoc(e)))for(r=h(o),s=h(e),a=0;null!=(i=s[a]);++a)r[a]&&k(i,r[a]);if(t)if(n)for(s=s||h(e),r=r||h(o),a=0;null!=(i=s[a]);a++)N(i,r[a]);else N(e,o);return r=h(o,\"script\"),r.length>0&&g(r,!u&&h(e,\"script\")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=pe.expando,u=pe.cache,l=fe.attributes,c=pe.event.special;null!=(n=e[a]);a++)if((t||He(n))&&(i=n[s],o=i&&u[i])){if(o.events)for(r in o.events)c[r]?pe.event.remove(n,r):pe.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||\"undefined\"==typeof n.removeAttribute?n[s]=void 0:n.removeAttribute(s),ne.push(i))}}}),pe.fn.extend({domManip:S,detach:function(e){return A(this,e,!0)},remove:function(e){return A(this,e)},text:function(e){return Pe(this,function(e){return void 0===e?pe.text(this):this.empty().append((this[0]&&this[0].ownerDocument||re).createTextNode(e))},null,e,arguments.length)},append:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.appendChild(e)}})},prepend:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&pe.cleanData(h(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&pe.nodeName(e,\"select\")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return pe.clone(this,e,t)})},html:function(e){return Pe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e)return 1===t.nodeType?t.innerHTML.replace(Ze,\"\"):void 0;if(\"string\"==typeof e&&!nt.test(e)&&(fe.htmlSerialize||!et.test(e))&&(fe.leadingWhitespace||!$e.test(e))&&!Xe[(We.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=pe.htmlPrefilter(e);try{for(;n<r;n++)t=this[n]||{},1===t.nodeType&&(pe.cleanData(h(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=[];return S(this,arguments,function(t){var n=this.parentNode;pe.inArray(this,e)<0&&(pe.cleanData(h(this)),\nn&&n.replaceChild(t,this))},e)}}),pe.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,t){pe.fn[e]=function(e){for(var n,r=0,i=[],o=pe(e),a=o.length-1;r<=a;r++)n=r===a?this:this.clone(!0),pe(o[r])[t](n),ae.apply(i,n.get());return this.pushStack(i)}});var ut,lt={HTML:\"block\",BODY:\"block\"},ct=/^margin/,ft=new RegExp(\"^(\"+Fe+\")(?!px)[a-z%]+$\",\"i\"),dt=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i},pt=re.documentElement;!function(){function t(){var t,c,f=re.documentElement;f.appendChild(u),l.style.cssText=\"-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%\",n=i=s=!1,r=a=!0,e.getComputedStyle&&(c=e.getComputedStyle(l),n=\"1%\"!==(c||{}).top,s=\"2px\"===(c||{}).marginLeft,i=\"4px\"===(c||{width:\"4px\"}).width,l.style.marginRight=\"50%\",r=\"4px\"===(c||{marginRight:\"4px\"}).marginRight,t=l.appendChild(re.createElement(\"div\")),t.style.cssText=l.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0\",t.style.marginRight=t.style.width=\"0\",l.style.width=\"1px\",a=!parseFloat((e.getComputedStyle(t)||{}).marginRight),l.removeChild(t)),l.style.display=\"none\",o=0===l.getClientRects().length,o&&(l.style.display=\"\",l.innerHTML=\"<table><tr><td></td><td>t</td></tr></table>\",t=l.getElementsByTagName(\"td\"),t[0].style.cssText=\"margin:0;border:0;padding:0;display:none\",o=0===t[0].offsetHeight,o&&(t[0].style.display=\"\",t[1].style.display=\"none\",o=0===t[0].offsetHeight)),f.removeChild(u)}var n,r,i,o,a,s,u=re.createElement(\"div\"),l=re.createElement(\"div\");l.style&&(l.style.cssText=\"float:left;opacity:.5\",fe.opacity=\"0.5\"===l.style.opacity,fe.cssFloat=!!l.style.cssFloat,l.style.backgroundClip=\"content-box\",l.cloneNode(!0).style.backgroundClip=\"\",fe.clearCloneStyle=\"content-box\"===l.style.backgroundClip,u=re.createElement(\"div\"),u.style.cssText=\"border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute\",l.innerHTML=\"\",u.appendChild(l),fe.boxSizing=\"\"===l.style.boxSizing||\"\"===l.style.MozBoxSizing||\"\"===l.style.WebkitBoxSizing,pe.extend(fe,{reliableHiddenOffsets:function(){return null==n&&t(),o},boxSizingReliable:function(){return null==n&&t(),i},pixelMarginRight:function(){return null==n&&t(),r},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),a},reliableMarginLeft:function(){return null==n&&t(),s}}))}();var ht,gt,mt=/^(top|right|bottom|left)$/;e.getComputedStyle?(ht=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n.getPropertyValue(t)||n[t]:void 0,\"\"!==a&&void 0!==a||pe.contains(e.ownerDocument,e)||(a=pe.style(e,t)),n&&!fe.pixelMarginRight()&&ft.test(a)&&ct.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o),void 0===a?a:a+\"\"}):pt.currentStyle&&(ht=function(e){return e.currentStyle},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n[t]:void 0,null==a&&s&&s[t]&&(a=s[t]),ft.test(a)&&!mt.test(t)&&(r=s.left,i=e.runtimeStyle,o=i&&i.left,o&&(i.left=e.currentStyle.left),s.left=\"fontSize\"===t?\"1em\":a,a=s.pixelLeft+\"px\",s.left=r,o&&(i.left=o)),void 0===a?a:a+\"\"||\"auto\"});var yt=/alpha\\([^)]*\\)/i,vt=/opacity\\s*=\\s*([^)]*)/i,xt=/^(none|table(?!-c[ea]).+)/,bt=new RegExp(\"^(\"+Fe+\")(.*)$\",\"i\"),wt={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Tt={letterSpacing:\"0\",fontWeight:\"400\"},Ct=[\"Webkit\",\"O\",\"Moz\",\"ms\"],Et=re.createElement(\"div\").style;pe.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=gt(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":fe.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=pe.camelCase(t),u=e.style;if(t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:u[t];if(o=typeof n,\"string\"===o&&(i=Me.exec(n))&&i[1]&&(n=d(e,t,i),o=\"number\"),null!=n&&n===n&&(\"number\"===o&&(n+=i&&i[3]||(pe.cssNumber[s]?\"\":\"px\")),fe.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(u[t]=\"inherit\"),!(a&&\"set\"in a&&void 0===(n=a.set(e,n,r)))))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o,a,s=pe.camelCase(t);return t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],a&&\"get\"in a&&(o=a.get(e,!0,n)),void 0===o&&(o=gt(e,t,r)),\"normal\"===o&&t in Tt&&(o=Tt[t]),\"\"===n||n?(i=parseFloat(o),n===!0||isFinite(i)?i||0:o):o}}),pe.each([\"height\",\"width\"],function(e,t){pe.cssHooks[t]={get:function(e,n,r){if(n)return xt.test(pe.css(e,\"display\"))&&0===e.offsetWidth?dt(e,wt,function(){return M(e,t,r)}):M(e,t,r)},set:function(e,n,r){var i=r&&ht(e);return _(e,n,r?F(e,t,r,fe.boxSizing&&\"border-box\"===pe.css(e,\"boxSizing\",!1,i),i):0)}}}),fe.opacity||(pe.cssHooks.opacity={get:function(e,t){return vt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||\"\")?.01*parseFloat(RegExp.$1)+\"\":t?\"1\":\"\"},set:function(e,t){var n=e.style,r=e.currentStyle,i=pe.isNumeric(t)?\"alpha(opacity=\"+100*t+\")\":\"\",o=r&&r.filter||n.filter||\"\";n.zoom=1,(t>=1||\"\"===t)&&\"\"===pe.trim(o.replace(yt,\"\"))&&n.removeAttribute&&(n.removeAttribute(\"filter\"),\"\"===t||r&&!r.filter)||(n.filter=yt.test(o)?o.replace(yt,i):o+\" \"+i)}}),pe.cssHooks.marginRight=L(fe.reliableMarginRight,function(e,t){if(t)return dt(e,{display:\"inline-block\"},gt,[e,\"marginRight\"])}),pe.cssHooks.marginLeft=L(fe.reliableMarginLeft,function(e,t){if(t)return(parseFloat(gt(e,\"marginLeft\"))||(pe.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-dt(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+\"px\"}),pe.each({margin:\"\",padding:\"\",border:\"Width\"},function(e,t){pe.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o=\"string\"==typeof n?n.split(\" \"):[n];r<4;r++)i[e+Oe[r]+t]=o[r]||o[r-2]||o[0];return i}},ct.test(e)||(pe.cssHooks[e+t].set=_)}),pe.fn.extend({css:function(e,t){return Pe(this,function(e,t,n){var r,i,o={},a=0;if(pe.isArray(t)){for(r=ht(e),i=t.length;a<i;a++)o[t[a]]=pe.css(e,t[a],!1,r);return o}return void 0!==n?pe.style(e,t,n):pe.css(e,t)},e,t,arguments.length>1)},show:function(){return q(this,!0)},hide:function(){return q(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){Re(this)?pe(this).show():pe(this).hide()})}}),pe.Tween=O,O.prototype={constructor:O,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||pe.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(pe.cssNumber[n]?\"\":\"px\")},cur:function(){var e=O.propHooks[this.prop];return e&&e.get?e.get(this):O.propHooks._default.get(this)},run:function(e){var t,n=O.propHooks[this.prop];return this.options.duration?this.pos=t=pe.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):O.propHooks._default.set(this),this}},O.prototype.init.prototype=O.prototype,O.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=pe.css(e.elem,e.prop,\"\"),t&&\"auto\"!==t?t:0)},set:function(e){pe.fx.step[e.prop]?pe.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[pe.cssProps[e.prop]]&&!pe.cssHooks[e.prop]?e.elem[e.prop]=e.now:pe.style(e.elem,e.prop,e.now+e.unit)}}},O.propHooks.scrollTop=O.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},pe.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},pe.fx=O.prototype.init,pe.fx.step={};var Nt,kt,St=/^(?:toggle|show|hide)$/,At=/queueHooks$/;pe.Animation=pe.extend($,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,Me.exec(t),n),n}]},tweener:function(e,t){pe.isFunction(e)?(t=e,e=[\"*\"]):e=e.match(De);for(var n,r=0,i=e.length;r<i;r++)n=e[r],$.tweeners[n]=$.tweeners[n]||[],$.tweeners[n].unshift(t)},prefilters:[W],prefilter:function(e,t){t?$.prefilters.unshift(e):$.prefilters.push(e)}}),pe.speed=function(e,t,n){var r=e&&\"object\"==typeof e?pe.extend({},e):{complete:n||!n&&t||pe.isFunction(e)&&e,duration:e,easing:n&&t||t&&!pe.isFunction(t)&&t};return r.duration=pe.fx.off?0:\"number\"==typeof r.duration?r.duration:r.duration in pe.fx.speeds?pe.fx.speeds[r.duration]:pe.fx.speeds._default,null!=r.queue&&r.queue!==!0||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){pe.isFunction(r.old)&&r.old.call(this),r.queue&&pe.dequeue(this,r.queue)},r},pe.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Re).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=pe.isEmptyObject(e),o=pe.speed(t,n,r),a=function(){var t=$(this,pe.extend({},e),o);(i||pe._data(this,\"finish\"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return\"string\"!=typeof e&&(n=t,t=e,e=void 0),t&&e!==!1&&this.queue(e||\"fx\",[]),this.each(function(){var t=!0,i=null!=e&&e+\"queueHooks\",o=pe.timers,a=pe._data(this);if(i)a[i]&&a[i].stop&&r(a[i]);else for(i in a)a[i]&&a[i].stop&&At.test(i)&&r(a[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||pe.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||\"fx\"),this.each(function(){var t,n=pe._data(this),r=n[e+\"queue\"],i=n[e+\"queueHooks\"],o=pe.timers,a=r?r.length:0;for(n.finish=!0,pe.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),pe.each([\"toggle\",\"show\",\"hide\"],function(e,t){var n=pe.fn[t];pe.fn[t]=function(e,r,i){return null==e||\"boolean\"==typeof e?n.apply(this,arguments):this.animate(P(t,!0),e,r,i)}}),pe.each({slideDown:P(\"show\"),slideUp:P(\"hide\"),slideToggle:P(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,t){pe.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),pe.timers=[],pe.fx.tick=function(){var e,t=pe.timers,n=0;for(Nt=pe.now();n<t.length;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||pe.fx.stop(),Nt=void 0},pe.fx.timer=function(e){pe.timers.push(e),e()?pe.fx.start():pe.timers.pop()},pe.fx.interval=13,pe.fx.start=function(){kt||(kt=e.setInterval(pe.fx.tick,pe.fx.interval))},pe.fx.stop=function(){e.clearInterval(kt),kt=null},pe.fx.speeds={slow:600,fast:200,_default:400},pe.fn.delay=function(t,n){return t=pe.fx?pe.fx.speeds[t]||t:t,n=n||\"fx\",this.queue(n,function(n,r){var i=e.setTimeout(n,t);r.stop=function(){e.clearTimeout(i)}})},function(){var e,t=re.createElement(\"input\"),n=re.createElement(\"div\"),r=re.createElement(\"select\"),i=r.appendChild(re.createElement(\"option\"));n=re.createElement(\"div\"),n.setAttribute(\"className\",\"t\"),n.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",e=n.getElementsByTagName(\"a\")[0],t.setAttribute(\"type\",\"checkbox\"),n.appendChild(t),e=n.getElementsByTagName(\"a\")[0],e.style.cssText=\"top:1px\",fe.getSetAttribute=\"t\"!==n.className,fe.style=/top/.test(e.getAttribute(\"style\")),fe.hrefNormalized=\"/a\"===e.getAttribute(\"href\"),fe.checkOn=!!t.value,fe.optSelected=i.selected,fe.enctype=!!re.createElement(\"form\").enctype,r.disabled=!0,fe.optDisabled=!i.disabled,t=re.createElement(\"input\"),t.setAttribute(\"value\",\"\"),fe.input=\"\"===t.getAttribute(\"value\"),t.value=\"t\",t.setAttribute(\"type\",\"radio\"),fe.radioValue=\"t\"===t.value}();var Dt=/\\r/g,jt=/[\\x20\\t\\r\\n\\f]+/g;pe.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=pe.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,pe(this).val()):e,null==i?i=\"\":\"number\"==typeof i?i+=\"\":pe.isArray(i)&&(i=pe.map(i,function(e){return null==e?\"\":e+\"\"})),t=pe.valHooks[this.type]||pe.valHooks[this.nodeName.toLowerCase()],t&&\"set\"in t&&void 0!==t.set(this,i,\"value\")||(this.value=i))});if(i)return t=pe.valHooks[i.type]||pe.valHooks[i.nodeName.toLowerCase()],t&&\"get\"in t&&void 0!==(n=t.get(i,\"value\"))?n:(n=i.value,\"string\"==typeof n?n.replace(Dt,\"\"):null==n?\"\":n)}}}),pe.extend({valHooks:{option:{get:function(e){var t=pe.find.attr(e,\"value\");return null!=t?t:pe.trim(pe.text(e)).replace(jt,\" \")}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o=\"select-one\"===e.type||i<0,a=o?null:[],s=o?i+1:r.length,u=i<0?s:o?i:0;u<s;u++)if(n=r[u],(n.selected||u===i)&&(fe.optDisabled?!n.disabled:null===n.getAttribute(\"disabled\"))&&(!n.parentNode.disabled||!pe.nodeName(n.parentNode,\"optgroup\"))){if(t=pe(n).val(),o)return t;a.push(t)}return a},set:function(e,t){for(var n,r,i=e.options,o=pe.makeArray(t),a=i.length;a--;)if(r=i[a],pe.inArray(pe.valHooks.option.get(r),o)>-1)try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),pe.each([\"radio\",\"checkbox\"],function(){pe.valHooks[this]={set:function(e,t){if(pe.isArray(t))return e.checked=pe.inArray(pe(e).val(),t)>-1}},fe.checkOn||(pe.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})});var Lt,Ht,qt=pe.expr.attrHandle,_t=/^(?:checked|selected)$/i,Ft=fe.getSetAttribute,Mt=fe.input;pe.fn.extend({attr:function(e,t){return Pe(this,pe.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){pe.removeAttr(this,e)})}}),pe.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?pe.prop(e,t,n):(1===o&&pe.isXMLDoc(e)||(t=t.toLowerCase(),i=pe.attrHooks[t]||(pe.expr.match.bool.test(t)?Ht:Lt)),void 0!==n?null===n?void pe.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:(r=pe.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!fe.radioValue&&\"radio\"===t&&pe.nodeName(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(De);if(o&&1===e.nodeType)for(;n=o[i++];)r=pe.propFix[n]||n,pe.expr.match.bool.test(n)?Mt&&Ft||!_t.test(n)?e[r]=!1:e[pe.camelCase(\"default-\"+n)]=e[r]=!1:pe.attr(e,n,\"\"),e.removeAttribute(Ft?n:r)}}),Ht={set:function(e,t,n){return t===!1?pe.removeAttr(e,n):Mt&&Ft||!_t.test(n)?e.setAttribute(!Ft&&pe.propFix[n]||n,n):e[pe.camelCase(\"default-\"+n)]=e[n]=!0,n}},pe.each(pe.expr.match.bool.source.match(/\\w+/g),function(e,t){var n=qt[t]||pe.find.attr;Mt&&Ft||!_t.test(t)?qt[t]=function(e,t,r){var i,o;return r||(o=qt[t],qt[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,qt[t]=o),i}:qt[t]=function(e,t,n){if(!n)return e[pe.camelCase(\"default-\"+t)]?t.toLowerCase():null}}),Mt&&Ft||(pe.attrHooks.value={set:function(e,t,n){return pe.nodeName(e,\"input\")?void(e.defaultValue=t):Lt&&Lt.set(e,t,n)}}),Ft||(Lt={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+=\"\",\"value\"===n||t===e.getAttribute(n))return t}},qt.id=qt.name=qt.coords=function(e,t,n){var r;if(!n)return(r=e.getAttributeNode(t))&&\"\"!==r.value?r.value:null},pe.valHooks.button={get:function(e,t){var n=e.getAttributeNode(t);if(n&&n.specified)return n.value},set:Lt.set},pe.attrHooks.contenteditable={set:function(e,t,n){Lt.set(e,\"\"!==t&&t,n)}},pe.each([\"width\",\"height\"],function(e,t){pe.attrHooks[t]={set:function(e,n){if(\"\"===n)return e.setAttribute(t,\"auto\"),n}}})),fe.style||(pe.attrHooks.style={get:function(e){return e.style.cssText||void 0},set:function(e,t){return e.style.cssText=t+\"\"}});var Ot=/^(?:input|select|textarea|button|object)$/i,Rt=/^(?:a|area)$/i;pe.fn.extend({prop:function(e,t){return Pe(this,pe.prop,e,t,arguments.length>1)},removeProp:function(e){return e=pe.propFix[e]||e,this.each(function(){try{this[e]=void 0,delete this[e]}catch(t){}})}}),pe.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&pe.isXMLDoc(e)||(t=pe.propFix[t]||t,i=pe.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=pe.find.attr(e,\"tabindex\");return t?parseInt(t,10):Ot.test(e.nodeName)||Rt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),fe.hrefNormalized||pe.each([\"href\",\"src\"],function(e,t){pe.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),fe.optSelected||(pe.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),pe.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){pe.propFix[this.toLowerCase()]=this}),fe.enctype||(pe.propFix.enctype=\"encoding\");var Pt=/[\\t\\r\\n\\f]/g;pe.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).addClass(e.call(this,t,z(this)))});if(\"string\"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(\" \"+i+\" \").replace(Pt,\" \")){for(a=0;o=t[a++];)r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");s=pe.trim(r),i!==s&&pe.attr(n,\"class\",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).removeClass(e.call(this,t,z(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if(\"string\"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(\" \"+i+\" \").replace(Pt,\" \")){for(a=0;o=t[a++];)for(;r.indexOf(\" \"+o+\" \")>-1;)r=r.replace(\" \"+o+\" \",\" \");s=pe.trim(r),i!==s&&pe.attr(n,\"class\",s)}return this},toggleClass:function(e,t){var n=typeof e;return\"boolean\"==typeof t&&\"string\"===n?t?this.addClass(e):this.removeClass(e):pe.isFunction(e)?this.each(function(n){pe(this).toggleClass(e.call(this,n,z(this),t),t)}):this.each(function(){var t,r,i,o;if(\"string\"===n)for(r=0,i=pe(this),o=e.match(De)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&\"boolean\"!==n||(t=z(this),t&&pe._data(this,\"__className__\",t),pe.attr(this,\"class\",t||e===!1?\"\":pe._data(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;for(t=\" \"+e+\" \";n=this[r++];)if(1===n.nodeType&&(\" \"+z(n)+\" \").replace(Pt,\" \").indexOf(t)>-1)return!0;return!1}}),pe.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(e,t){pe.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),pe.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var Bt=e.location,Wt=pe.now(),It=/\\?/,$t=/(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g;pe.parseJSON=function(t){if(e.JSON&&e.JSON.parse)return e.JSON.parse(t+\"\");var n,r=null,i=pe.trim(t+\"\");return i&&!pe.trim(i.replace($t,function(e,t,i,o){return n&&t&&(r=0),0===r?e:(n=i||t,r+=!o-!i,\"\")}))?Function(\"return \"+i)():pe.error(\"Invalid JSON: \"+t)},pe.parseXML=function(t){var n,r;if(!t||\"string\"!=typeof t)return null;try{e.DOMParser?(r=new e.DOMParser,n=r.parseFromString(t,\"text/xml\")):(n=new e.ActiveXObject(\"Microsoft.XMLDOM\"),n.async=\"false\",n.loadXML(t))}catch(i){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName(\"parsererror\").length||pe.error(\"Invalid XML: \"+t),n};var zt=/#.*$/,Xt=/([?&])_=[^&]*/,Ut=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/gm,Vt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Yt=/^(?:GET|HEAD)$/,Jt=/^\\/\\//,Gt=/^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,Kt={},Qt={},Zt=\"*/\".concat(\"*\"),en=Bt.href,tn=Gt.exec(en.toLowerCase())||[];pe.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:en,type:\"GET\",isLocal:Vt.test(tn[1]),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Zt,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":pe.parseJSON,\"text xml\":pe.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?V(V(e,pe.ajaxSettings),t):V(pe.ajaxSettings,e)},ajaxPrefilter:X(Kt),ajaxTransport:X(Qt),ajax:function(t,n){function r(t,n,r,i){var o,f,v,x,w,C=n;2!==b&&(b=2,u&&e.clearTimeout(u),c=void 0,s=i||\"\",T.readyState=t>0?4:0,o=t>=200&&t<300||304===t,r&&(x=Y(d,T,r)),x=J(d,x,T,o),o?(d.ifModified&&(w=T.getResponseHeader(\"Last-Modified\"),w&&(pe.lastModified[a]=w),w=T.getResponseHeader(\"etag\"),w&&(pe.etag[a]=w)),204===t||\"HEAD\"===d.type?C=\"nocontent\":304===t?C=\"notmodified\":(C=x.state,f=x.data,v=x.error,o=!v)):(v=C,!t&&C||(C=\"error\",t<0&&(t=0))),T.status=t,T.statusText=(n||C)+\"\",o?g.resolveWith(p,[f,C,T]):g.rejectWith(p,[T,C,v]),T.statusCode(y),y=void 0,l&&h.trigger(o?\"ajaxSuccess\":\"ajaxError\",[T,d,o?f:v]),m.fireWith(p,[T,C]),l&&(h.trigger(\"ajaxComplete\",[T,d]),--pe.active||pe.event.trigger(\"ajaxStop\")))}\"object\"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,d=pe.ajaxSetup({},n),p=d.context||d,h=d.context&&(p.nodeType||p.jquery)?pe(p):pe.event,g=pe.Deferred(),m=pe.Callbacks(\"once memory\"),y=d.statusCode||{},v={},x={},b=0,w=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!f)for(f={};t=Ut.exec(s);)f[t[1].toLowerCase()]=t[2];t=f[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?s:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=x[n]=x[n]||e,v[e]=t),this},overrideMimeType:function(e){return b||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)y[t]=[y[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||w;return c&&c.abort(t),r(0,t),this}};if(g.promise(T).complete=m.add,T.success=T.done,T.error=T.fail,d.url=((t||d.url||en)+\"\").replace(zt,\"\").replace(Jt,tn[1]+\"//\"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=pe.trim(d.dataType||\"*\").toLowerCase().match(De)||[\"\"],null==d.crossDomain&&(i=Gt.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===tn[1]&&i[2]===tn[2]&&(i[3]||(\"http:\"===i[1]?\"80\":\"443\"))===(tn[3]||(\"http:\"===tn[1]?\"80\":\"443\")))),d.data&&d.processData&&\"string\"!=typeof d.data&&(d.data=pe.param(d.data,d.traditional)),U(Kt,d,n,T),2===b)return T;l=pe.event&&d.global,l&&0===pe.active++&&pe.event.trigger(\"ajaxStart\"),d.type=d.type.toUpperCase(),d.hasContent=!Yt.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(It.test(a)?\"&\":\"?\")+d.data,delete d.data),d.cache===!1&&(d.url=Xt.test(a)?a.replace(Xt,\"$1_=\"+Wt++):a+(It.test(a)?\"&\":\"?\")+\"_=\"+Wt++)),d.ifModified&&(pe.lastModified[a]&&T.setRequestHeader(\"If-Modified-Since\",pe.lastModified[a]),pe.etag[a]&&T.setRequestHeader(\"If-None-Match\",pe.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&T.setRequestHeader(\"Content-Type\",d.contentType),T.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(\"*\"!==d.dataTypes[0]?\", \"+Zt+\"; q=0.01\":\"\"):d.accepts[\"*\"]);for(o in d.headers)T.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(p,T,d)===!1||2===b))return T.abort();w=\"abort\";for(o in{success:1,error:1,complete:1})T[o](d[o]);if(c=U(Qt,d,n,T)){if(T.readyState=1,l&&h.trigger(\"ajaxSend\",[T,d]),2===b)return T;d.async&&d.timeout>0&&(u=e.setTimeout(function(){T.abort(\"timeout\")},d.timeout));try{b=1,c.send(v,r)}catch(C){if(!(b<2))throw C;r(-1,C)}}else r(-1,\"No Transport\");return T},getJSON:function(e,t,n){return pe.get(e,t,n,\"json\")},getScript:function(e,t){return pe.get(e,void 0,t,\"script\")}}),pe.each([\"get\",\"post\"],function(e,t){pe[t]=function(e,n,r,i){return pe.isFunction(n)&&(i=i||r,r=n,n=void 0),pe.ajax(pe.extend({url:e,type:t,dataType:i,data:n,success:r},pe.isPlainObject(e)&&e))}}),pe._evalUrl=function(e){return pe.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,\"throws\":!0})},pe.fn.extend({wrapAll:function(e){if(pe.isFunction(e))return this.each(function(t){pe(this).wrapAll(e.call(this,t))});if(this[0]){var t=pe(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return pe.isFunction(e)?this.each(function(t){pe(this).wrapInner(e.call(this,t))}):this.each(function(){var t=pe(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=pe.isFunction(e);return this.each(function(n){pe(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){pe.nodeName(this,\"body\")||pe(this).replaceWith(this.childNodes)}).end()}}),pe.expr.filters.hidden=function(e){return fe.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:K(e)},pe.expr.filters.visible=function(e){return!pe.expr.filters.hidden(e)};var nn=/%20/g,rn=/\\[\\]$/,on=/\\r?\\n/g,an=/^(?:submit|button|image|reset|file)$/i,sn=/^(?:input|select|textarea|keygen)/i;pe.param=function(e,t){var n,r=[],i=function(e,t){t=pe.isFunction(t)?t():null==t?\"\":t,r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(t)};if(void 0===t&&(t=pe.ajaxSettings&&pe.ajaxSettings.traditional),pe.isArray(e)||e.jquery&&!pe.isPlainObject(e))pe.each(e,function(){i(this.name,this.value)});else for(n in e)Q(n,e[n],t,i);return r.join(\"&\").replace(nn,\"+\")},pe.fn.extend({serialize:function(){return pe.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=pe.prop(this,\"elements\");return e?pe.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!pe(this).is(\":disabled\")&&sn.test(this.nodeName)&&!an.test(e)&&(this.checked||!Be.test(e))}).map(function(e,t){var n=pe(this).val();return null==n?null:pe.isArray(n)?pe.map(n,function(e){return{name:t.name,value:e.replace(on,\"\\r\\n\")}}):{name:t.name,value:n.replace(on,\"\\r\\n\")}}).get()}}),pe.ajaxSettings.xhr=void 0!==e.ActiveXObject?function(){return this.isLocal?ee():re.documentMode>8?Z():/^(get|post|head|put|delete|options)$/i.test(this.type)&&Z()||ee()}:Z;var un=0,ln={},cn=pe.ajaxSettings.xhr();e.attachEvent&&e.attachEvent(\"onunload\",function(){for(var e in ln)ln[e](void 0,!0)}),fe.cors=!!cn&&\"withCredentials\"in cn,cn=fe.ajax=!!cn,cn&&pe.ajaxTransport(function(t){if(!t.crossDomain||fe.cors){var n;return{send:function(r,i){var o,a=t.xhr(),s=++un;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||r[\"X-Requested-With\"]||(r[\"X-Requested-With\"]=\"XMLHttpRequest\");for(o in r)void 0!==r[o]&&a.setRequestHeader(o,r[o]+\"\");a.send(t.hasContent&&t.data||null),n=function(e,r){var o,u,l;if(n&&(r||4===a.readyState))if(delete ln[s],n=void 0,a.onreadystatechange=pe.noop,r)4!==a.readyState&&a.abort();else{l={},o=a.status,\"string\"==typeof a.responseText&&(l.text=a.responseText);try{u=a.statusText}catch(c){u=\"\"}o||!t.isLocal||t.crossDomain?1223===o&&(o=204):o=l.text?200:404}l&&i(o,u,l,a.getAllResponseHeaders())},t.async?4===a.readyState?e.setTimeout(n):a.onreadystatechange=ln[s]=n:n()},abort:function(){n&&n(void 0,!0)}}}}),pe.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return pe.globalEval(e),e}}}),pe.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\",e.global=!1)}),pe.ajaxTransport(\"script\",function(e){if(e.crossDomain){var t,n=re.head||pe(\"head\")[0]||re.documentElement;return{send:function(r,i){t=re.createElement(\"script\"),t.async=!0,e.scriptCharset&&(t.charset=e.scriptCharset),t.src=e.url,t.onload=t.onreadystatechange=function(e,n){(n||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),t=null,n||i(200,\"success\"))},n.insertBefore(t,n.firstChild)},abort:function(){t&&t.onload(void 0,!0)}}}});var fn=[],dn=/(=)\\?(?=&|$)|\\?\\?/;pe.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=fn.pop()||pe.expando+\"_\"+Wt++;return this[e]=!0,e}}),pe.ajaxPrefilter(\"json jsonp\",function(t,n,r){var i,o,a,s=t.jsonp!==!1&&(dn.test(t.url)?\"url\":\"string\"==typeof t.data&&0===(t.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&dn.test(t.data)&&\"data\");if(s||\"jsonp\"===t.dataTypes[0])return i=t.jsonpCallback=pe.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(dn,\"$1\"+i):t.jsonp!==!1&&(t.url+=(It.test(t.url)?\"&\":\"?\")+t.jsonp+\"=\"+i),t.converters[\"script json\"]=function(){return a||pe.error(i+\" was not called\"),a[0]},t.dataTypes[0]=\"json\",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?pe(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,fn.push(i)),a&&pe.isFunction(o)&&o(a[0]),a=o=void 0}),\"script\"}),pe.parseHTML=function(e,t,n){if(!e||\"string\"!=typeof e)return null;\"boolean\"==typeof t&&(n=t,t=!1),t=t||re;var r=Te.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=y([e],t,i),i&&i.length&&pe(i).remove(),pe.merge([],r.childNodes))};var pn=pe.fn.load;return pe.fn.load=function(e,t,n){if(\"string\"!=typeof e&&pn)return pn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(\" \");return s>-1&&(r=pe.trim(e.slice(s,e.length)),e=e.slice(0,s)),pe.isFunction(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),a.length>0&&pe.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?pe(\"<div>\").append(pe.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},pe.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){pe.fn[t]=function(e){return this.on(t,e)}}),pe.expr.filters.animated=function(e){return pe.grep(pe.timers,function(t){return e===t.elem}).length},pe.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=pe.css(e,\"position\"),f=pe(e),d={};\"static\"===c&&(e.style.position=\"relative\"),s=f.offset(),o=pe.css(e,\"top\"),u=pe.css(e,\"left\"),l=(\"absolute\"===c||\"fixed\"===c)&&pe.inArray(\"auto\",[o,u])>-1,l?(r=f.position(),a=r.top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),pe.isFunction(t)&&(t=t.call(e,n,pe.extend({},s))),null!=t.top&&(d.top=t.top-s.top+a),null!=t.left&&(d.left=t.left-s.left+i),\"using\"in t?t.using.call(e,d):f.css(d)}},pe.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){pe.offset.setOffset(this,e,t)});var t,n,r={top:0,left:0},i=this[0],o=i&&i.ownerDocument;if(o)return t=o.documentElement,pe.contains(t,i)?(\"undefined\"!=typeof i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=te(o),{top:r.top+(n.pageYOffset||t.scrollTop)-(t.clientTop||0),left:r.left+(n.pageXOffset||t.scrollLeft)-(t.clientLeft||0)}):r},position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return\"fixed\"===pe.css(r,\"position\")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),pe.nodeName(e[0],\"html\")||(n=e.offset()),n.top+=pe.css(e[0],\"borderTopWidth\",!0),n.left+=pe.css(e[0],\"borderLeftWidth\",!0)),{top:t.top-n.top-pe.css(r,\"marginTop\",!0),left:t.left-n.left-pe.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){\nfor(var e=this.offsetParent;e&&!pe.nodeName(e,\"html\")&&\"static\"===pe.css(e,\"position\");)e=e.offsetParent;return e||pt})}}),pe.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(e,t){var n=/Y/.test(t);pe.fn[e]=function(r){return Pe(this,function(e,r,i){var o=te(e);return void 0===i?o?t in o?o[t]:o.document.documentElement[r]:e[r]:void(o?o.scrollTo(n?pe(o).scrollLeft():i,n?i:pe(o).scrollTop()):e[r]=i)},e,r,arguments.length,null)}}),pe.each([\"top\",\"left\"],function(e,t){pe.cssHooks[t]=L(fe.pixelPosition,function(e,n){if(n)return n=gt(e,t),ft.test(n)?pe(e).position()[t]+\"px\":n})}),pe.each({Height:\"height\",Width:\"width\"},function(e,t){pe.each({padding:\"inner\"+e,content:t,\"\":\"outer\"+e},function(n,r){pe.fn[r]=function(r,i){var o=arguments.length&&(n||\"boolean\"!=typeof r),a=n||(r===!0||i===!0?\"margin\":\"border\");return Pe(this,function(t,n,r){var i;return pe.isWindow(t)?t.document.documentElement[\"client\"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body[\"scroll\"+e],i[\"scroll\"+e],t.body[\"offset\"+e],i[\"offset\"+e],i[\"client\"+e])):void 0===r?pe.css(t,n,a):pe.style(t,n,r,a)},t,o?r:void 0,o,null)}})}),pe.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),pe.fn.size=function(){return this.length},pe.fn.andSelf=pe.fn.addBack,layui.define(function(e){layui.$=pe,e(\"jquery\",pe)}),pe});!function(e,t){\"use strict\";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if(\"interactive\"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],type:[\"dialog\",\"page\",\"iframe\",\"loading\",\"tips\"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName(\"head\")[0],s=document.createElement(\"link\");\"string\"==typeof i&&(n=i);var l=(n||t).replace(/\\.|\\//g,\"\"),f=\"layuicss-\"+l,c=0;s.rel=\"stylesheet\",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),\"function\"==typeof i&&!function u(){return++c>80?e.console&&console.error(\"layer.css: Invalid\"):void(1989===parseInt(o.getStyle(document.getElementById(f),\"width\"))?i():setTimeout(u,100))}()}}},r={v:\"3.1.1\",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||\"ActiveXObject\"in e)&&((t.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,\"string\"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss(\"modules/layer/\"+e.extend):o.link(\"theme/\"+e.extend),this):this},ready:function(e){var t=\"layer\",i=\"\",n=(a?\"modules/layer/\":\"theme/\")+\"default/layer.css?v=\"+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a=\"function\"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s=\"function\"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s=\"function\"==typeof n,f=o.config.skin,c=(f?f+\" \"+f+\"-msg\":\"\")||\"layui-layer-msg\",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+\" layui-layer-hui\",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+\" \"+(n.skin||\"layui-layer-hui\")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=[\"layui-layer\",\".layui-layer-title\",\".layui-layer-main\",\".layui-layer-dialog\",\"layui-layer-iframe\",\"layui-layer-content\",\"layui-layer-btn\",\"layui-layer-close\"];l.anim=[\"layer-anim-00\",\"layer-anim-01\",\"layer-anim-02\",\"layer-anim-03\",\"layer-anim-04\",\"layer-anim-05\",\"layer-anim-06\"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:\"&#x4FE1;&#x606F;\",offset:\"auto\",area:\"auto\",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f=\"object\"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'<div class=\"layui-layer-title\" style=\"'+(f?r.title[1]:\"\")+'\">'+(f?r.title[0]:r.title)+\"</div>\":\"\";return r.zIndex=s,t([r.shade?'<div class=\"layui-layer-shade\" id=\"layui-layer-shade'+a+'\" times=\"'+a+'\" style=\"'+(\"z-index:\"+(s-1)+\"; \")+'\"></div>':\"\",'<div class=\"'+l[0]+(\" layui-layer-\"+o.type[r.type])+(0!=r.type&&2!=r.type||r.shade?\"\":\" layui-layer-border\")+\" \"+(r.skin||\"\")+'\" id=\"'+l[0]+a+'\" type=\"'+o.type[r.type]+'\" times=\"'+a+'\" showtime=\"'+r.time+'\" conType=\"'+(e?\"object\":\"string\")+'\" style=\"z-index: '+s+\"; width:\"+r.area[0]+\";height:\"+r.area[1]+(r.fixed?\"\":\";position:absolute;\")+'\">'+(e&&2!=r.type?\"\":u)+'<div id=\"'+(r.id||\"\")+'\" class=\"layui-layer-content'+(0==r.type&&r.icon!==-1?\" layui-layer-padding\":\"\")+(3==r.type?\" layui-layer-loading\"+r.icon:\"\")+'\">'+(0==r.type&&r.icon!==-1?'<i class=\"layui-layer-ico layui-layer-ico'+r.icon+'\"></i>':\"\")+(1==r.type&&e?\"\":r.content||\"\")+'</div><span class=\"layui-layer-setwin\">'+function(){var e=c?'<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>':\"\";return r.closeBtn&&(e+='<a class=\"layui-layer-ico '+l[7]+\" \"+l[7]+(r.title?r.closeBtn:4==r.type?\"1\":\"2\")+'\" href=\"javascript:;\"></a>'),e}()+\"</span>\"+(r.btn?function(){var e=\"\";\"string\"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t<i;t++)e+='<a class=\"'+l[6]+t+'\">'+r.btn[t]+\"</a>\";return'<div class=\"'+l[6]+\" layui-layer-btn-\"+(r.btnAlign||\"\")+'\">'+e+\"</div>\"}():\"\")+(r.resize?'<span class=\"layui-layer-resize\"></span>':\"\")+\"</div>\"],u,i('<div class=\"layui-layer-move\"></div>')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f=\"object\"==typeof s,c=i(\"body\");if(!t.id||!i(\"#\"+t.id)[0]){switch(\"string\"==typeof t.area&&(t.area=\"auto\"===t.area?[\"\",\"\"]:[t.area,\"\"]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn=\"btn\"in t?t.btn:o.btn[0],r.closeAll(\"dialog\");break;case 2:var s=t.content=f?t.content:[t.content||\"\",\"auto\"];t.content='<iframe scrolling=\"'+(t.content[1]||\"auto\")+'\" allowtransparency=\"true\" id=\"'+l[4]+a+'\" name=\"'+l[4]+a+'\" onload=\"this.className=\\'\\';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"'+t.content[0]+'\"></iframe>';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll(\"loading\");break;case 4:f||(t.content=[t.content,\"body\"]),t.follow=t.content[1],t.content=t.content[0]+'<i class=\"layui-layer-TipsG\"></i>',delete t.title,t.tips=\"object\"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll(\"tips\")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i(\"body\").append(n[1])}():function(){s.parents(\".\"+l[0])[0]||(s.data(\"display\",s.css(\"display\")).show().addClass(\"layui-layer-wrap\").wrap(n[1]),i(\"#\"+l[0]+a).find(\".\"+l[5]).before(r))}()}():c.append(n[1]),i(\".layui-layer-move\")[0]||c.append(o.moveElem=u),e.layero=i(\"#\"+l[0]+a),t.scrollbar||l.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",a)}).auto(a),i(\"#layui-layer-shade\"+e.index).css({\"background-color\":t.shade[1]||\"#000\",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find(\"iframe\").attr(\"src\",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on(\"resize\",function(){e.offset(),(/^\\d+%$/.test(t.area[0])||/^\\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u=\"layer-anim \"+l.anim[t.anim];e.layero.addClass(u).one(\"webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend\",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data(\"isOutAnim\",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i(\"#\"+l[0]+e);\"\"===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find(\".\"+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css(\"padding-top\"))))};switch(a.type){case 2:u(\"iframe\");break;default:\"\"===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u(\".\"+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u(\".\"+l[5])):u(\".\"+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o=\"object\"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):\"auto\"!==t.offset&&(\"t\"===t.offset?e.offsetTop=0:\"r\"===t.offset?e.offsetLeft=n.width()-a[0]:\"b\"===t.offset?e.offsetTop=n.height()-a[1]:\"l\"===t.offset?e.offsetLeft=0:\"lt\"===t.offset?(e.offsetTop=0,e.offsetLeft=0):\"lb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):\"rt\"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):\"rb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr(\"minLeft\")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css(\"left\")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i(\"body\"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(\".layui-layer-TipsG\"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:\"auto\"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass(\"layui-layer-TipsB\").addClass(\"layui-layer-TipsT\").css(\"border-right-color\",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass(\"layui-layer-TipsL\").addClass(\"layui-layer-TipsR\").css(\"border-bottom-color\",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass(\"layui-layer-TipsT\").addClass(\"layui-layer-TipsB\").css(\"border-right-color\",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass(\"layui-layer-TipsR\").addClass(\"layui-layer-TipsL\").css(\"border-bottom-color\",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find(\".\"+l[5]).css({\"background-color\":t.tips[1],\"padding-right\":t.closeBtn?\"30px\":\"\"}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(\".layui-layer-resize\"),c={};return t.move&&l.css(\"cursor\",\"move\"),l.on(\"mousedown\",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css(\"left\")),e.clientY-parseFloat(s.css(\"top\"))],o.moveElem.css(\"cursor\",\"move\").show())}),f.on(\"mousedown\",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css(\"cursor\",\"se-resize\").show()}),a.on(\"mousemove\",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l=\"fixed\"===s.css(\"position\");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;a<c.stX&&(a=c.stX),a>f&&(a=f),o<c.stY&&(o=c.stY),o>u&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on(\"mouseup\",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find(\"iframe\").on(\"load\",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find(\".\"+l[6]).children(\"a\").on(\"click\",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a[\"btn\"+(e+1)]&&a[\"btn\"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find(\".\"+l[7]).on(\"click\",e),a.shadeClose&&i(\"#layui-layer-shade\"+t.index).on(\"click\",function(){r.close(t.index)}),n.find(\".layui-layer-min\").on(\"click\",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(\".layui-layer-max\").on(\"click\",function(){i(this).hasClass(\"layui-layer-maxmin\")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i(\"select\"),function(e,t){var n=i(this);n.parents(\".\"+l[0])[0]||1==n.attr(\"layer\")&&i(\".\"+l[0]).length<1&&n.removeAttr(\"layer\").show(),n=null})},s.pt.IE6=function(e){i(\"select\").each(function(e,t){var n=i(this);n.parents(\".\"+l[0])[0]||\"none\"===n.css(\"display\")||n.attr({layer:\"1\"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css(\"z-index\",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on(\"mousedown\",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css(\"margin-left\"))];e.find(\".layui-layer-max\").addClass(\"layui-layer-maxmin\"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr(\"layer-full\")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty(\"overflow\"):l.html[0].style.removeAttribute(\"overflow\"),l.html.removeAttr(\"layer-full\"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i(\".\"+l[4]).attr(\"times\"),i(\"#\"+l[0]+t).find(\"iframe\").contents().find(e)},r.getFrameIndex=function(e){return i(\"#\"+e).parents(\".\"+l[4]).attr(\"times\")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame(\"html\",e).outerHeight(),n=i(\"#\"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find(\".\"+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find(\"iframe\").css({height:t})}},r.iframeSrc=function(e,t){i(\"#\"+l[0]+e).find(\"iframe\").attr(\"src\",t)},r.style=function(e,t,n){var a=i(\"#\"+l[0]+e),r=a.find(\".layui-layer-content\"),s=a.attr(\"type\"),f=a.find(l[1]).outerHeight()||0,c=a.find(\".\"+l[6]).outerHeight()||0;a.attr(\"minLeft\");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find(\".\"+l[6]).outerHeight(),s===o.type[2]?a.find(\"iframe\").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css(\"padding-top\"))-parseFloat(r.css(\"padding-bottom\"))}))},r.min=function(e,t){var a=i(\"#\"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr(\"minLeft\")||181*o.minIndex+\"px\",c=a.css(\"position\");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr(\"position\",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:\"fixed\",overflow:\"hidden\"},!0),a.find(\".layui-layer-min\").hide(),\"page\"===a.attr(\"type\")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr(\"minLeft\")||o.minIndex++,a.attr(\"minLeft\",f)},r.restore=function(e){var t=i(\"#\"+l[0]+e),n=t.attr(\"area\").split(\",\");t.attr(\"type\");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr(\"position\"),overflow:\"visible\"},!0),t.find(\".layui-layer-max\").removeClass(\"layui-layer-maxmin\"),t.find(\".layui-layer-min\").show(),\"page\"===t.attr(\"type\")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i(\"#\"+l[0]+e);o.record(a),l.html.attr(\"layer-full\")||l.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",e),clearTimeout(t),t=setTimeout(function(){var t=\"fixed\"===a.css(\"position\");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(\".layui-layer-min\").hide()},100)},r.title=function(e,t){var n=i(\"#\"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i(\"#\"+l[0]+e),n=t.attr(\"type\"),a=\"layer-anim-close\";if(t[0]){var s=\"layui-layer-wrap\",f=function(){if(n===o.type[1]&&\"object\"===t.attr(\"conType\")){t.children(\":not(.\"+l[5]+\")\").remove();for(var a=t.find(\".\"+s),r=0;r<2;r++)a.unwrap();a.css(\"display\",a.data(\"display\")).removeClass(s)}else{if(n===o.type[2])try{var f=i(\"#\"+l[4]+e)[0];f.contentWindow.document.write(\"\"),f.contentWindow.close(),t.find(\".\"+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML=\"\",t.remove()}\"function\"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data(\"isOutAnim\")&&t.addClass(\"layer-anim \"+a),i(\"#layui-layer-moves, #layui-layer-shade\"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr(\"minLeft\")&&(o.minIndex--,o.minLeft.push(t.attr(\"minLeft\"))),r.ie&&r.ie<10||!t.data(\"isOutAnim\")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i(\".\"+l[0]),function(){var t=i(this),n=e?t.attr(\"type\")===e:1;n&&r.close(t.attr(\"times\")),n=null})};var f=r.cache||{},c=function(e){return f.skin?\" \"+f.skin+\" \"+f.skin+\"-\"+e:\"\"};r.prompt=function(e,t){var a=\"\";if(e=e||{},\"function\"==typeof e&&(t=e),e.area){var o=e.area;a='style=\"width: '+o[0]+\"; height: \"+o[1]+';\"',delete e.area}var s,l=2==e.formType?'<textarea class=\"layui-layer-input\"'+a+\"></textarea>\":function(){return'<input type=\"'+(1==e.formType?\"password\":\"text\")+'\" class=\"layui-layer-input\">'}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:l,skin:\"layui-layer-prompt\"+c(\"prompt\"),maxWidth:n.width(),success:function(t){s=t.find(\".layui-layer-input\"),s.val(e.value||\"\").focus(),\"function\"==typeof f&&f(t)},resize:!1,yes:function(i){var n=s.val();\"\"===n?s.focus():n.length>(e.maxlength||500)?r.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(e.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n=\"layui-this\",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:\"layui-layer-tab\"+c(\"tab\"),resize:!1,title:function(){var e=t.length,i=1,a=\"\";if(e>0)for(a='<span class=\"'+n+'\">'+t[0].title+\"</span>\";i<e;i++)a+=\"<span>\"+t[i].title+\"</span>\";return a}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var e=t.length,i=1,a=\"\";if(e>0)for(a='<li class=\"layui-layer-tabli '+n+'\">'+(t[0].content||\"no content\")+\"</li>\";i<e;i++)a+='<li class=\"layui-layer-tabli\">'+(t[i].content||\"no  content\")+\"</li>\";return a}()+\"</ul>\",success:function(t){var o=t.find(\".layui-layer-title\").children(),r=t.find(\".layui-layer-tabmain\").children();o.on(\"mousedown\",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),\"function\"==typeof e.change&&e.change(o)}),\"function\"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||\"img\";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr(\"layer-index\",e),u.push({alt:t.attr(\"alt\"),pid:t.attr(\"layer-pid\"),src:t.attr(\"layer-src\")||t.attr(\"src\"),thumb:t.attr(\"src\")})})};if(h(),0===u.length)return;if(n||p.on(\"click\",t.img,function(){var e=i(this),n=e.attr(\"layer-index\");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(e){e.preventDefault(),s.imgnext()}),i(document).on(\"keyup\",s.keyup)},s.loadi=r.load(1,{shade:!(\"shade\"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:\"layui-layer-photos\",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]<r[1]&&(a[0]=a[0]/r[1],a[1]=a[1]/r[1])}return[a[0]+\"px\",a[1]+\"px\"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:\".layui-layer-phimg img\",moveType:1,scrollbar:!1,moveOut:!0,isOutAnim:!1,skin:\"layui-layer-photos\"+c(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+u[d].src+'\" alt=\"'+(u[d].alt||\"\")+'\" layer-pid=\"'+u[d].pid+'\"><div class=\"layui-layer-imgsee\">'+(u.length>1?'<span class=\"layui-layer-imguide\"><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgprev\"></a><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgnext\"></a></span>':\"\")+'<div class=\"layui-layer-imgbar\" style=\"display:'+(a?\"block\":\"\")+'\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">'+(u[d].alt||\"\")+\"</a><em>\"+s.imgIndex+\"/\"+u.length+\"</em></span></div></div></div>\",success:function(e,i){s.bigimg=e.find(\".layui-layer-phimg\"),s.imgsee=e.find(\".layui-layer-imguide,.layui-layer-imgbar\"),s.event(e),t.tab&&t.tab(u[d],e),\"function\"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off(\"keyup\",s.keyup)}},t))},function(){r.close(s.loadi),r.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"&#x4E0B;&#x4E00;&#x5F20;\",\"&#x4E0D;&#x770B;&#x4E86;\"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i(\"html\"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define(\"jquery\",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t(\"layer\",r)})):\"function\"==typeof define&&define.amd?define([\"jquery\"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);layui.define(\"jquery\",function(t){\"use strict\";var a=layui.$,i=(layui.hint(),layui.device()),e=\"element\",l=\"layui-this\",n=\"layui-show\",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=\".layui-tab-title\",l=a(\".layui-tab[lay-filter=\"+t+\"]\"),n=l.children(e),s=n.children(\".layui-tab-bar\"),o=l.children(\".layui-tab-content\"),r='<li lay-id=\"'+(i.id||\"\")+'\"'+(i.attr?' lay-attr=\"'+i.attr+'\"':\"\")+\">\"+(i.title||\"unnaming\")+\"</li>\";return s[0]?s.before(r):n.append(r),o.append('<div class=\"layui-tab-item\">'+(i.content||\"\")+\"</div>\"),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=\".layui-tab-title\",l=a(\".layui-tab[lay-filter=\"+t+\"]\"),n=l.children(e),s=n.find('>li[lay-id=\"'+i+'\"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=\".layui-tab-title\",l=a(\".layui-tab[lay-filter=\"+t+\"]\"),n=l.children(e),s=n.find('>li[lay-id=\"'+i+'\"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on(\"click\",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e=\"layui-progress\",l=a(\".\"+e+\"[lay-filter=\"+t+\"]\"),n=l.find(\".\"+e+\"-bar\"),s=n.find(\".\"+e+\"-text\");return n.css(\"width\",i),s.text(i),this};var o=\".layui-nav\",r=\"layui-nav-item\",c=\"layui-nav-bar\",u=\"layui-nav-tree\",d=\"layui-nav-child\",y=\"layui-nav-more\",h=\"layui-anim layui-anim-upbit\",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children(\"li\").index(r),c=o.headerElem?r.parent():r.parents(\".layui-tab\").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(\".layui-tab-content\").children(\".layui-tab-item\"),d=r.find(\"a\"),y=c.attr(\"lay-filter\");\"javascript:;\"!==d.attr(\"href\")&&\"_blank\"===d.attr(\"target\")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,\"tab(\"+y+\")\",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(\".layui-tab\").eq(0),r=o.children(\".layui-tab-content\").children(\".layui-tab-item\"),c=o.attr(\"lay-filter\");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,\"tabDelete(\"+c+\")\",{elem:o,index:s})},tabAuto:function(){var t=\"layui-tab-more\",e=\"layui-tab-bar\",l=\"layui-tab-close\",n=this;a(\".layui-tab\").each(function(){var s=a(this),o=s.children(\".layui-tab-title\"),r=(s.children(\".layui-tab-content\").children(\".layui-tab-item\"),'lay-stope=\"tabmore\"'),c=a('<span class=\"layui-unselect layui-tab-bar\" '+r+\"><i \"+r+' class=\"layui-icon\">&#xe61a;</i></span>');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr(\"lay-allowClose\")&&o.find(\"li\").each(function(){var t=a(this);if(!t.find(\".\"+l)[0]){var i=a('<i class=\"layui-icon layui-unselect '+l+'\">&#x1006;</i>');i.on(\"click\",f.tabDelete),t.append(i)}}),\"string\"!=typeof s.attr(\"lay-unauto\"))if(o.prop(\"scrollWidth\")>o.outerWidth()+1){if(o.find(\".\"+e)[0])return;o.append(c),s.attr(\"overflow\",\"\"),c.on(\"click\",function(a){o[this.title?\"removeClass\":\"addClass\"](t),this.title=this.title?\"\":\"收缩\"})}else o.find(\".\"+e).remove(),s.removeAttr(\"overflow\")})},hideTabMore:function(t){var i=a(\".layui-tab-title\");t!==!0&&\"tabmore\"===a(t.target).attr(\"lay-stope\")||(i.removeClass(\"layui-tab-more\"),i.find(\".layui-tab-bar\").attr(\"title\",\"\"))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr(\"lay-filter\"),s=t.parent(),c=t.siblings(\".\"+d),y=\"string\"==typeof s.attr(\"lay-unselect\");\"javascript:;\"!==t.attr(\"href\")&&\"_blank\"===t.attr(\"target\")||y||c[0]||(i.find(\".\"+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s[\"none\"===c.css(\"display\")?\"addClass\":\"removeClass\"](r+\"ed\"),\"all\"===i.attr(\"lay-shrink\")&&s.siblings().removeClass(r+\"ed\"))),layui.event.call(this,e,\"nav(\"+n+\")\",t)},collapse:function(){var t=a(this),i=t.find(\".layui-colla-icon\"),l=t.siblings(\".layui-colla-content\"),s=t.parents(\".layui-collapse\").eq(0),o=s.attr(\"lay-filter\"),r=\"none\"===l.css(\"display\");if(\"string\"==typeof s.attr(\"lay-accordion\")){var c=s.children(\".layui-colla-item\").children(\".\"+n);c.siblings(\".layui-colla-title\").children(\".layui-colla-icon\").html(\"&#xe602;\"),c.removeClass(n)}l[r?\"addClass\":\"removeClass\"](n),i.html(r?\"&#xe61a;\":\"&#xe602;\"),layui.event.call(this,e,\"collapse(\"+o+\")\",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter=\"'+e+'\"]':\"\"}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find(\".\"+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children(\"a\").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css(\"marginLeft\")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),\"block\"===f.css(\"display\")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find(\".\"+y).addClass(y+\"d\")},300))};a(o+l).each(function(i){var l=a(this),o=a('<span class=\"'+c+'\"></span>'),h=l.find(\".\"+r);l.find(\".\"+c)[0]||(l.append(o),h.on(\"mouseenter\",function(){b.call(this,o,l,i)}).on(\"mouseleave\",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find(\".\"+d).removeClass(n),l.find(\".\"+y).removeClass(y+\"d\")},300))}),l.on(\"mouseleave\",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find(\"a\").each(function(){var t=a(this),i=(t.parent(),t.siblings(\".\"+d));i[0]&&!t.children(\".\"+y)[0]&&t.append('<span class=\"'+y+'\"></span>'),t.off(\"click\",f.clickThis).on(\"click\",f.clickThis)})})},breadcrumb:function(){var t=\".layui-breadcrumb\";a(t+l).each(function(){var t=a(this),i=\"lay-separator\",e=t.attr(i)||\"/\",l=t.find(\"a\");l.next(\"span[\"+i+\"]\")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(\"<span \"+i+\">\"+e+\"</span>\")}),t.css(\"visibility\",\"visible\"))})},progress:function(){var t=\"layui-progress\";a(\".\"+t+l).each(function(){var i=a(this),e=i.find(\".layui-progress-bar\"),l=e.attr(\"lay-percent\");e.css(\"width\",function(){return/^.+\\/.+$/.test(l)?100*new Function(\"return \"+l)()+\"%\":l}()),i.attr(\"lay-showPercent\")&&setTimeout(function(){e.html('<span class=\"'+t+'-text\">'+l+\"</span>\")},350)})},collapse:function(){var t=\"layui-collapse\";a(\".\"+t+l).each(function(){var t=a(this).find(\".layui-colla-item\");t.each(function(){var t=a(this),i=t.find(\".layui-colla-title\"),e=t.find(\".layui-colla-content\"),l=\"none\"===e.css(\"display\");i.find(\".layui-colla-icon\").remove(),i.append('<i class=\"layui-icon layui-colla-icon\">'+(l?\"&#xe602;\":\"&#xe61a;\")+\"</i>\"),i.off(\"click\",f.collapse).on(\"click\",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=\".layui-tab-title li\";b.on(\"click\",v,f.tabClick),b.on(\"click\",f.hideTabMore),a(window).on(\"resize\",f.tabAuto),t(e,p)});layui.define(\"layer\",function(e){\"use strict\";var t=layui.$,i=layui.layer,n=layui.hint(),a=layui.device(),o={config:{},set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,r,e,t)}},l=function(){var e=this;return{upload:function(t){e.upload.call(e,t)},reload:function(t){e.reload.call(e,t)},config:e.config}},r=\"upload\",u=\"layui-upload-file\",c=\"layui-upload-form\",f=\"layui-upload-iframe\",s=\"layui-upload-choose\",p=function(e){var i=this;i.config=t.extend({},i.config,o.config,e),i.render()};p.prototype.config={accept:\"images\",exts:\"\",auto:!0,bindAction:\"\",url:\"\",field:\"file\",acceptMime:\"\",method:\"post\",data:{},drag:!0,size:0,number:0,multiple:!1},p.prototype.render=function(e){var i=this,e=i.config;e.elem=t(e.elem),e.bindAction=t(e.bindAction),i.file(),i.events()},p.prototype.file=function(){var e=this,i=e.config,n=e.elemFile=t(['<input class=\"'+u+'\" type=\"file\" accept=\"'+i.acceptMime+'\" name=\"'+i.field+'\"',i.multiple?\" multiple\":\"\",\">\"].join(\"\")),o=i.elem.next();(o.hasClass(u)||o.hasClass(c))&&o.remove(),a.ie&&a.ie<10&&i.elem.wrap('<div class=\"layui-upload-wrap\"></div>'),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(n),a.ie&&a.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,i=e.config,n=t('<iframe id=\"'+f+'\" class=\"'+f+'\" name=\"'+f+'\" frameborder=\"0\"></iframe>'),a=t(['<form target=\"'+f+'\" class=\"'+c+'\" method=\"post\" key=\"set-mine\" enctype=\"multipart/form-data\" action=\"'+i.url+'\">',\"</form>\"].join(\"\"));t(\"#\"+f)[0]||t(\"body\").append(n),i.elem.next().hasClass(c)||(e.elemFile.wrap(a),i.elem.next(\".\"+c).append(function(){var e=[];return layui.each(i.data,function(t,i){i=\"function\"==typeof i?i():i,e.push('<input type=\"hidden\" name=\"'+t+'\" value=\"'+i+'\">')}),e.join(\"\")}()))},p.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return\"input\"===e.tagName.toLocaleLowerCase()&&\"file\"===e.type},p.prototype.preview=function(e){var t=this;window.FileReader&&layui.each(t.chooseFiles,function(t,i){var n=new FileReader;n.readAsDataURL(i),n.onload=function(){e&&e(t,i,this.result)}})},p.prototype.upload=function(e,i){var n,o=this,l=o.config,r=o.elemFile[0],u=function(){var i=0,n=0,a=e||o.files||o.chooseFiles||r.files,u=function(){l.multiple&&i+n===o.fileLength&&\"function\"==typeof l.allDone&&l.allDone({total:o.fileLength,successful:i,aborted:n})};layui.each(a,function(e,a){var r=new FormData;r.append(l.field,a),layui.each(l.data,function(e,t){t=\"function\"==typeof t?t():t,r.append(e,t)}),t.ajax({url:l.url,type:\"post\",data:r,contentType:!1,processData:!1,dataType:\"json\",headers:l.headers||{},success:function(t){i++,d(e,t),u()},error:function(){n++,o.msg(\"请求上传接口出现异常\"),m(e),u()}})})},c=function(){var e=t(\"#\"+f);o.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var t,i=e.contents().find(\"body\");try{t=i.text()}catch(n){o.msg(\"获取上传后的响应信息出现异常\"),clearInterval(p.timer),m()}t&&(clearInterval(p.timer),i.html(\"\"),d(0,t))},30)},d=function(e,t){if(o.elemFile.next(\".\"+s).remove(),r.value=\"\",\"object\"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},o.msg(\"请对上传接口返回有效JSON\")}\"function\"==typeof l.done&&l.done(t,e||0,function(e){o.upload(e)})},m=function(e){l.auto&&(r.value=\"\"),\"function\"==typeof l.error&&l.error(e||0,function(e){o.upload(e)})},h=l.exts,v=function(){var t=[];return layui.each(e||o.chooseFiles,function(e,i){t.push(i.name)}),t}(),g={preview:function(e){o.preview(e)},upload:function(e,t){var i={};i[e]=t,o.upload(i)},pushFile:function(){return o.files=o.files||{},layui.each(o.chooseFiles,function(e,t){o.files[e]=t}),o.files},resetFile:function(e,t,i){var n=new File([t],i);o.files=o.files||{},o.files[e]=n}},y=function(){if(\"choose\"!==i&&!l.auto||(l.choose&&l.choose(g),\"choose\"!==i))return l.before&&l.before(g),a.ie?a.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\\/\\\\]+\\..+/g)||[]||\"\":v,0!==v.length){switch(l.accept){case\"file\":if(h&&!RegExp(\"\\\\w\\\\.(\"+h+\")$\",\"i\").test(escape(v)))return o.msg(\"选择的文件中包含不支持的格式\"),r.value=\"\";break;case\"video\":if(!RegExp(\"\\\\w\\\\.(\"+(h||\"avi|mp4|wma|rmvb|rm|flash|3gp|flv\")+\")$\",\"i\").test(escape(v)))return o.msg(\"选择的视频中包含不支持的格式\"),r.value=\"\";break;case\"audio\":if(!RegExp(\"\\\\w\\\\.(\"+(h||\"mp3|wav|mid\")+\")$\",\"i\").test(escape(v)))return o.msg(\"选择的音频中包含不支持的格式\"),r.value=\"\";break;default:if(layui.each(v,function(e,t){RegExp(\"\\\\w\\\\.(\"+(h||\"jpg|png|gif|bmp|jpeg$\")+\")\",\"i\").test(escape(t))||(n=!0)}),n)return o.msg(\"选择的图片中包含不支持的格式\"),r.value=\"\"}if(o.fileLength=function(){var t=0,i=e||o.files||o.chooseFiles||r.files;return layui.each(i,function(){t++}),t}(),l.number&&o.fileLength>l.number)return o.msg(\"同时最多只能上传的数量为：\"+l.number);if(l.size>0&&!(a.ie&&a.ie<10)){var F;if(layui.each(o.chooseFiles,function(e,t){if(t.size>1024*l.size){var i=l.size/1024;i=i>=1?i.toFixed(2)+\"MB\":l.size+\"KB\",r.value=\"\",F=i}}),F)return o.msg(\"文件不能超过\"+F)}y()}},p.prototype.reload=function(e){e=e||{},delete e.elem,delete e.bindAction;var i=this,e=i.config=t.extend({},i.config,o.config,e),n=e.elem.next();n.attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},p.prototype.events=function(){var e=this,i=e.config,o=function(t){e.chooseFiles={},layui.each(t,function(t,i){var n=(new Date).getTime();e.chooseFiles[n+\"-\"+t]=i})},l=function(t,n){var a=e.elemFile,o=t.length>1?t.length+\"个文件\":(t[0]||{}).name||a[0].value.match(/[^\\/\\\\]+\\..+/g)||[]||\"\";a.next().hasClass(s)&&a.next().remove(),e.upload(null,\"choose\"),e.isFile()||i.choose||a.after('<span class=\"layui-inline '+s+'\">'+o+\"</span>\")};i.elem.off(\"upload.start\").on(\"upload.start\",function(){var a=t(this),o=a.attr(\"lay-data\");if(o)try{o=new Function(\"return \"+o)(),e.config=t.extend({},i,o)}catch(l){n.error(\"Upload element property lay-data configuration item has a syntax error: \"+o)}e.config.item=a,e.elemFile[0].click()}),a.ie&&a.ie<10||i.elem.off(\"upload.over\").on(\"upload.over\",function(){var e=t(this);e.attr(\"lay-over\",\"\")}).off(\"upload.leave\").on(\"upload.leave\",function(){var e=t(this);e.removeAttr(\"lay-over\")}).off(\"upload.drop\").on(\"upload.drop\",function(n,a){var r=t(this),u=a.originalEvent.dataTransfer.files||[];r.removeAttr(\"lay-over\"),o(u),i.auto?e.upload(u):l(u)}),e.elemFile.off(\"upload.change\").on(\"upload.change\",function(){var t=this.files||[];o(t),i.auto?e.upload():l(t)}),i.bindAction.off(\"upload.action\").on(\"upload.action\",function(){e.upload()}),i.elem.data(\"haveEvents\")||(e.elemFile.on(\"change\",function(){t(this).trigger(\"upload.change\")}),i.elem.on(\"click\",function(){e.isFile()||t(this).trigger(\"upload.start\")}),i.drag&&i.elem.on(\"dragover\",function(e){e.preventDefault(),t(this).trigger(\"upload.over\")}).on(\"dragleave\",function(e){t(this).trigger(\"upload.leave\")}).on(\"drop\",function(e){e.preventDefault(),t(this).trigger(\"upload.drop\",e)}),i.bindAction.on(\"click\",function(){t(this).trigger(\"upload.action\")}),i.elem.data(\"haveEvents\",!0))},o.render=function(e){var t=new p(e);return l.call(t)},e(r,o)});layui.define(\"jquery\",function(e){\"use strict\";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(i,t){return e.slide(\"set\",i,t||0)},config:i}},n=\"slider\",l=\"layui-disabled\",s=\"layui-slider\",r=\"layui-slider-bar\",o=\"layui-slider-wrap\",u=\"layui-slider-wrap-btn\",d=\"layui-slider-tips\",v=\"layui-slider-input\",c=\"layui-slider-input-txt\",m=\"layui-slider-input-btn\",p=\"layui-slider-hover\",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.prototype.config={type:\"default\",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:\"#009688\"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.max<t.min&&(t.max=t.min+t.step),t.range){t.value=\"object\"==typeof t.value?t.value:[t.min,t.value];var a=Math.min(t.value[0],t.value[1]),n=Math.max(t.value[0],t.value[1]);t.value[0]=a>t.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+\"%\";r+=\"%\",v+=\"%\"}else{\"object\"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.value<t.min&&(t.value=t.min),t.value>t.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+\"%\"}var p=t.disabled?\"#c2c2c2\":t.theme,f='<div class=\"layui-slider '+(\"vertical\"===t.type?\"layui-slider-vertical\":\"\")+'\">'+(t.tips?'<div class=\"layui-slider-tips\"></div>':\"\")+'<div class=\"layui-slider-bar\" style=\"background:'+p+\"; \"+(\"vertical\"===t.type?\"height\":\"width\")+\":\"+m+\";\"+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+(r||0)+';\"></div><div class=\"layui-slider-wrap\" style=\"'+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+(r||m)+';\"><div class=\"layui-slider-wrap-btn\" style=\"border: 2px solid '+p+';\"></div></div>'+(t.range?'<div class=\"layui-slider-wrap\" style=\"'+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+v+';\"><div class=\"layui-slider-wrap-btn\" style=\"border: 2px solid '+p+';\"></div></div>':\"\")+\"</div>\",h=i(t.elem),y=h.next(\".\"+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find(\".\"+o).eq(0).data(\"value\",t.value[0]),e.elemTemp.find(\".\"+o).eq(1).data(\"value\",t.value[1])):e.elemTemp.find(\".\"+o).data(\"value\",t.value),h.html(e.elemTemp),\"vertical\"===t.type&&e.elemTemp.height(t.height+\"px\"),t.showstep){for(var g=(t.max-t.min)/t.step,b=\"\",x=1;x<g+1;x++){var T=100*x/g;T<100&&(b+='<div class=\"layui-slider-step\" style=\"'+(\"vertical\"===t.type?\"bottom\":\"left\")+\":\"+T+'%\"></div>')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('<div class=\"layui-slider-input layui-input\"><div class=\"layui-slider-input-txt\"><input type=\"text\" class=\"layui-input\"></div><div class=\"layui-slider-input-btn\"><i class=\"layui-icon layui-icon-up\"></i><i class=\"layui-icon layui-icon-down\"></i></div></div>');h.css(\"position\",\"relative\"),h.append(w),h.find(\".\"+c).children(\"input\").val(t.value),\"vertical\"===t.type?w.css({left:0,top:-48}):e.elemTemp.css(\"margin-right\",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find(\".\"+u).addClass(l)):e.slide(),e.elemTemp.find(\".\"+u).on(\"mouseover\",function(){var a=\"vertical\"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find(\".\"+o),l=\"vertical\"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data(\"value\"),u=t.setTips?t.setTips(r):r;e.elemTemp.find(\".\"+d).html(u),\"vertical\"===t.type?e.elemTemp.find(\".\"+d).css({bottom:s+\"%\",\"margin-bottom\":\"20px\",display:\"inline-block\"}):e.elemTemp.find(\".\"+d).css({left:s+\"%\",display:\"inline-block\"})}).on(\"mouseout\",function(){e.elemTemp.find(\".\"+d).css(\"display\",\"none\")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return\"vertical\"===l.type?l.height:s[0].offsetWidth},h=s.find(\".\"+o),y=s.next(\".\"+v),g=y.children(\".\"+c).children(\"input\").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css(\"vertical\"===l.type?\"bottom\":\"left\",e+\"%\");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;\"vertical\"===l.type?(s.find(\".\"+d).css({bottom:e+\"%\",\"margin-bottom\":\"20px\"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find(\".\"+d).css(\"left\",e+\"%\"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);\"vertical\"===l.type?s.find(\".\"+r).css({height:o+\"%\",bottom:n+\"%\"}):s.find(\".\"+r).css({width:o+\"%\",left:n+\"%\"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children(\".\"+c).children(\"input\").val(g),h.eq(i).data(\"value\",u),u=l.setTips?l.setTips(u):u,s.find(\".\"+d).html(u),l.range){var v=[h.eq(0).data(\"value\"),h.eq(1).data(\"value\")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['<div class=\"layui-auxiliar-moving\" id=\"LAY-slider-moving\"></div'].join(\"\")),M=function(e,t){var a=function(){t&&t(),w.remove()};i(\"#LAY-slider-moving\")[0]||i(\"body\").append(w),w.on(\"mousemove\",e),w.on(\"mouseup\",a).on(\"mouseleave\",a)};if(\"set\"===e)return x(t,a);s.find(\".\"+u).each(function(e){var t=i(this);t.on(\"mousedown\",function(i){i=i||window.event;var a=t.parent()[0].offsetLeft,n=i.clientX;\"vertical\"===l.type&&(a=f()-t.parent()[0].offsetTop-h.height(),n=i.clientY);var r=function(i){i=i||window.event;var r=a+(\"vertical\"===l.type?n-i.clientY:i.clientX-n);r<0&&(r=0),r>f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find(\".\"+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find(\".\"+d).hide()};M(r,o)})}),s.on(\"click\",function(e){var t=i(\".\"+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n=\"vertical\"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?\"vertical\"===l.type?Math.abs(n-parseInt(i(h[0]).css(\"bottom\")))>Math.abs(n-parseInt(i(h[1]).css(\"bottom\")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children(\".\"+m).fadeIn(\"fast\")},function(){var e=i(this);e.children(\".\"+m).fadeOut(\"fast\")}),y.children(\".\"+m).children(\"i\").each(function(e){i(this).on(\"click\",function(){g=1==e?g-l.step<l.min?l.min:Number(g)-l.step:Number(g)+l.step>l.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=e<l.min?l.min:e,e=e>l.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children(\".\"+c).children(\"input\").on(\"keydown\",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on(\"change\",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)});layui.define(\"jquery\",function(e){\"use strict\";var i=layui.jquery,o={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var o=this;return o.config=i.extend({},o.config,e),o},on:function(e,i){return layui.onevent.call(this,\"colorpicker\",e,i)}},r=function(){var e=this,i=e.config;return{config:i}},t=\"colorpicker\",n=\"layui-show\",l=\"layui-colorpicker\",c=\".layui-colorpicker-main\",a=\"layui-icon-down\",s=\"layui-icon-close\",f=\"layui-colorpicker-trigger-span\",d=\"layui-colorpicker-trigger-i\",u=\"layui-colorpicker-side\",p=\"layui-colorpicker-side-slider\",g=\"layui-colorpicker-basis\",v=\"layui-colorpicker-alpha-bgcolor\",h=\"layui-colorpicker-alpha-slider\",m=\"layui-colorpicker-basis-cursor\",b=\"layui-colorpicker-main-input\",k=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),t=r-o;return i.b=r,i.s=0!=r?255*t/r:0,0!=i.s?e.r==r?i.h=(e.g-e.b)/t:e.g==r?i.h=2+(e.b-e.r)/t:i.h=4+(e.r-e.g)/t:i.h=-1,r==o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},y=function(e){var e=e.indexOf(\"#\")>-1?e.substring(1):e;if(3==e.length){var i=e.split(\"\");e=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]}e=parseInt(e,16);var o={r:e>>16,g:(65280&e)>>8,b:255&e};return k(o)},x=function(e){var i={},o=e.h,r=255*e.s/100,t=255*e.b/100;if(0==r)i.r=i.g=i.b=t;else{var n=t,l=(255-r)*t/255,c=(n-l)*(o%60)/60;360==o&&(o=0),o<60?(i.r=n,i.b=l,i.g=l+c):o<120?(i.g=n,i.b=l,i.r=n-c):o<180?(i.g=n,i.r=l,i.b=l+c):o<240?(i.b=n,i.r=l,i.g=n-c):o<300?(i.b=n,i.g=l,i.r=l+c):o<360?(i.r=n,i.g=l,i.b=n-c):(i.r=0,i.g=0,i.b=0)}return{r:Math.round(i.r),g:Math.round(i.g),b:Math.round(i.b)}},C=function(e){var o=x(e),r=[o.r.toString(16),o.g.toString(16),o.b.toString(16)];return i.each(r,function(e,i){1==i.length&&(r[e]=\"0\"+i)}),r.join(\"\")},P=function(e){var i=/[0-9]{1,3}/g,o=e.match(i)||[];return{r:o[0],g:o[1],b:o[2]}},B=i(window),w=i(document),D=function(e){var r=this;r.index=++o.index,r.config=i.extend({},r.config,o.config,e),r.render()};D.prototype.config={color:\"\",size:null,alpha:!1,format:\"hex\",predefine:!1,colors:[\"#009688\",\"#5FB878\",\"#1E9FFF\",\"#FF5722\",\"#FFB800\",\"#01AAED\",\"#999\",\"#c00\",\"#ff8c00\",\"#ffd700\",\"#90ee90\",\"#00ced1\",\"#1e90ff\",\"#c71585\",\"rgb(0, 186, 189)\",\"rgb(255, 120, 0)\",\"rgb(250, 212, 0)\",\"#393D49\",\"rgba(0,0,0,.5)\",\"rgba(255, 69, 0, 0.68)\",\"rgba(144, 240, 144, 0.5)\",\"rgba(31, 147, 255, 0.73)\"]},D.prototype.render=function(){var e=this,o=e.config,r=i(['<div class=\"layui-unselect layui-colorpicker\">',\"<span \"+(\"rgb\"==o.format&&o.alpha?'class=\"layui-colorpicker-trigger-bgcolor\"':\"\")+\">\",'<span class=\"layui-colorpicker-trigger-span\" ','lay-type=\"'+(\"rgb\"==o.format?o.alpha?\"rgba\":\"torgb\":\"\")+'\" ','style=\"'+function(){var e=\"\";return o.color?(e=o.color,(o.color.match(/[0-9]{1,3}/g)||[]).length>3&&(o.alpha&&\"rgb\"==o.format||(e=\"#\"+C(k(P(o.color))))),\"background: \"+e):e}()+'\">','<i class=\"layui-icon layui-colorpicker-trigger-i '+(o.color?a:s)+'\"></i>',\"</span>\",\"</span>\",\"</div>\"].join(\"\")),t=i(o.elem);o.size&&r.addClass(\"layui-colorpicker-\"+o.size),t.addClass(\"layui-inline\").html(e.elemColorBox=r),e.color=e.elemColorBox.find(\".\"+f)[0].style.background,e.events()},D.prototype.renderPicker=function(){var e=this,o=e.config,r=e.elemColorBox[0],t=e.elemPicker=i(['<div id=\"layui-colorpicker'+e.index+'\" data-index=\"'+e.index+'\" class=\"layui-anim layui-anim-upbit layui-colorpicker-main\">','<div class=\"layui-colorpicker-main-wrapper\">','<div class=\"layui-colorpicker-basis\">','<div class=\"layui-colorpicker-basis-white\"></div>','<div class=\"layui-colorpicker-basis-black\"></div>','<div class=\"layui-colorpicker-basis-cursor\"></div>',\"</div>\",'<div class=\"layui-colorpicker-side\">','<div class=\"layui-colorpicker-side-slider\"></div>',\"</div>\",\"</div>\",'<div class=\"layui-colorpicker-main-alpha '+(o.alpha?n:\"\")+'\">','<div class=\"layui-colorpicker-alpha-bgcolor\">','<div class=\"layui-colorpicker-alpha-slider\"></div>',\"</div>\",\"</div>\",function(){if(o.predefine){var e=['<div class=\"layui-colorpicker-main-pre\">'];return layui.each(o.colors,function(i,o){e.push(['<div class=\"layui-colorpicker-pre'+((o.match(/[0-9]{1,3}/g)||[]).length>3?\" layui-colorpicker-pre-isalpha\":\"\")+'\">','<div style=\"background:'+o+'\"></div>',\"</div>\"].join(\"\"))}),e.push(\"</div>\"),e.join(\"\")}return\"\"}(),'<div class=\"layui-colorpicker-main-input\">','<div class=\"layui-inline\">','<input type=\"text\" class=\"layui-input\">',\"</div>\",'<div class=\"layui-btn-container\">','<button class=\"layui-btn layui-btn-primary layui-btn-sm\" colorpicker-events=\"clear\">清空</button>','<button class=\"layui-btn layui-btn-sm\" colorpicker-events=\"confirm\">确定</button>',\"</div\",\"</div>\",\"</div>\"].join(\"\"));e.elemColorBox.find(\".\"+f)[0];i(c)[0]&&i(c).data(\"index\")==e.index?e.removePicker(D.thisElemInd):(e.removePicker(D.thisElemInd),i(\"body\").append(t)),D.thisElemInd=e.index,D.thisColor=r.style.background,e.position(),e.pickerEvents()},D.prototype.removePicker=function(e){var o=this;o.config;return i(\"#layui-colorpicker\"+(e||o.index)).remove(),o},D.prototype.position=function(){var e=this,i=e.config,o=e.bindElem||e.elemColorBox[0],r=e.elemPicker[0],t=o.getBoundingClientRect(),n=r.offsetWidth,l=r.offsetHeight,c=function(e){return e=e?\"scrollLeft\":\"scrollTop\",document.body[e]|document.documentElement[e]},a=function(e){return document.documentElement[e?\"clientWidth\":\"clientHeight\"]},s=5,f=t.left,d=t.bottom;f-=(n-o.offsetWidth)/2,d+=s,f+n+s>a(\"width\")?f=a(\"width\")-n-s:f<s&&(f=s),d+l+s>a()&&(d=t.top>l?t.top-l:a()-l,d-=2*s),i.position&&(r.style.position=i.position),r.style.left=f+(\"fixed\"===i.position?0:c(1))+\"px\",r.style.top=d+(\"fixed\"===i.position?0:c())+\"px\"},D.prototype.val=function(){var e=this,i=(e.config,e.elemColorBox.find(\".\"+f)),o=e.elemPicker.find(\".\"+b),r=i[0],t=r.style.backgroundColor;if(t){var n=k(P(t)),l=i.attr(\"lay-type\");if(e.select(n.h,n.s,n.b),\"torgb\"===l&&o.find(\"input\").val(t),\"rgba\"===l){var c=P(t);if(3==(t.match(/[0-9]{1,3}/g)||[]).length)o.find(\"input\").val(\"rgba(\"+c.r+\", \"+c.g+\", \"+c.b+\", 1)\"),e.elemPicker.find(\".\"+h).css(\"left\",280);else{o.find(\"input\").val(t);var a=280*t.slice(t.lastIndexOf(\",\")+1,t.length-1);e.elemPicker.find(\".\"+h).css(\"left\",a)}e.elemPicker.find(\".\"+v)[0].style.background=\"linear-gradient(to right, rgba(\"+c.r+\", \"+c.g+\", \"+c.b+\", 0), rgb(\"+c.r+\", \"+c.g+\", \"+c.b+\"))\"}}else e.select(0,100,100),o.find(\"input\").val(\"\"),e.elemPicker.find(\".\"+v)[0].style.background=\"\",e.elemPicker.find(\".\"+h).css(\"left\",280)},D.prototype.side=function(){var e=this,o=e.config,r=e.elemColorBox.find(\".\"+f),t=r.attr(\"lay-type\"),n=e.elemPicker.find(\".\"+u),l=e.elemPicker.find(\".\"+p),c=e.elemPicker.find(\".\"+g),y=e.elemPicker.find(\".\"+m),C=e.elemPicker.find(\".\"+v),w=e.elemPicker.find(\".\"+h),D=l[0].offsetTop/180*360,E=100-(y[0].offsetTop+3)/180*100,H=(y[0].offsetLeft+3)/260*100,W=Math.round(w[0].offsetLeft/280*100)/100,j=e.elemColorBox.find(\".\"+d),F=e.elemPicker.find(\".layui-colorpicker-pre\").children(\"div\"),L=function(i,n,l,c){e.select(i,n,l);var f=x({h:i,s:n,b:l});if(j.addClass(a).removeClass(s),r[0].style.background=\"rgb(\"+f.r+\", \"+f.g+\", \"+f.b+\")\",\"torgb\"===t&&e.elemPicker.find(\".\"+b).find(\"input\").val(\"rgb(\"+f.r+\", \"+f.g+\", \"+f.b+\")\"),\"rgba\"===t){var d=0;d=280*c,w.css(\"left\",d),e.elemPicker.find(\".\"+b).find(\"input\").val(\"rgba(\"+f.r+\", \"+f.g+\", \"+f.b+\", \"+c+\")\"),r[0].style.background=\"rgba(\"+f.r+\", \"+f.g+\", \"+f.b+\", \"+c+\")\",C[0].style.background=\"linear-gradient(to right, rgba(\"+f.r+\", \"+f.g+\", \"+f.b+\", 0), rgb(\"+f.r+\", \"+f.g+\", \"+f.b+\"))\"}o.change&&o.change(e.elemPicker.find(\".\"+b).find(\"input\").val())},M=i(['<div class=\"layui-auxiliar-moving\" id=\"LAY-colorpicker-moving\"></div'].join(\"\")),Y=function(e){i(\"#LAY-colorpicker-moving\")[0]||i(\"body\").append(M),M.on(\"mousemove\",e),M.on(\"mouseup\",function(){M.remove()}).on(\"mouseleave\",function(){M.remove()})};l.on(\"mousedown\",function(e){var i=this.offsetTop,o=e.clientY,r=function(e){var r=i+(e.clientY-o),t=n[0].offsetHeight;r<0&&(r=0),r>t&&(r=t);var l=r/180*360;D=l,L(l,H,E,W),e.preventDefault()};Y(r),e.preventDefault()}),n.on(\"click\",function(e){var o=e.clientY-i(this).offset().top;o<0&&(o=0),o>this.offsetHeight&&(o=this.offsetHeight);var r=o/180*360;D=r,L(r,H,E,W),e.preventDefault()}),y.on(\"mousedown\",function(e){var i=this.offsetTop,o=this.offsetLeft,r=e.clientY,t=e.clientX,n=function(e){var n=i+(e.clientY-r),l=o+(e.clientX-t),a=c[0].offsetHeight-3,s=c[0].offsetWidth-3;n<-3&&(n=-3),n>a&&(n=a),l<-3&&(l=-3),l>s&&(l=s);var f=(l+3)/260*100,d=100-(n+3)/180*100;E=d,H=f,L(D,f,d,W),e.preventDefault()};layui.stope(e),Y(n),e.preventDefault()}),c.on(\"mousedown\",function(e){var o=e.clientY-i(this).offset().top-3+B.scrollTop(),r=e.clientX-i(this).offset().left-3+B.scrollLeft();o<-3&&(o=-3),o>this.offsetHeight-3&&(o=this.offsetHeight-3),r<-3&&(r=-3),r>this.offsetWidth-3&&(r=this.offsetWidth-3);var t=(r+3)/260*100,n=100-(o+3)/180*100;E=n,H=t,L(D,t,n,W),e.preventDefault(),y.trigger(e,\"mousedown\")}),w.on(\"mousedown\",function(e){var i=this.offsetLeft,o=e.clientX,r=function(e){var r=i+(e.clientX-o),t=C[0].offsetWidth;r<0&&(r=0),r>t&&(r=t);var n=Math.round(r/280*100)/100;W=n,L(D,H,E,n),e.preventDefault()};Y(r),e.preventDefault()}),C.on(\"click\",function(e){var o=e.clientX-i(this).offset().left;o<0&&(o=0),o>this.offsetWidth&&(o=this.offsetWidth);var r=Math.round(o/280*100)/100;W=r,L(D,H,E,r),e.preventDefault()}),F.each(function(){i(this).on(\"click\",function(){i(this).parent(\".layui-colorpicker-pre\").addClass(\"selected\").siblings().removeClass(\"selected\");var e,o=this.style.backgroundColor,r=k(P(o)),t=o.slice(o.lastIndexOf(\",\")+1,o.length-1);D=r.h,H=r.s,E=r.b,3==(o.match(/[0-9]{1,3}/g)||[]).length&&(t=1),W=t,e=280*t,L(r.h,r.s,r.b,t)})})},D.prototype.select=function(e,i,o,r){var t=this,n=(t.config,C({h:e,s:100,b:100})),l=C({h:e,s:i,b:o}),c=e/360*180,a=180-o/100*180-3,s=i/100*260-3;t.elemPicker.find(\".\"+p).css(\"top\",c),t.elemPicker.find(\".\"+g)[0].style.background=\"#\"+n,t.elemPicker.find(\".\"+m).css({top:a,left:s}),\"change\"!==r&&t.elemPicker.find(\".\"+b).find(\"input\").val(\"#\"+l)},D.prototype.pickerEvents=function(){var e=this,o=e.config,r=e.elemColorBox.find(\".\"+f),t=e.elemPicker.find(\".\"+b+\" input\"),n={clear:function(i){r[0].style.background=\"\",e.elemColorBox.find(\".\"+d).removeClass(a).addClass(s),e.color=\"\",o.done&&o.done(\"\"),e.removePicker()},confirm:function(i,n){var l=t.val(),c=l,f={};if(l.indexOf(\",\")>-1){if(f=k(P(l)),e.select(f.h,f.s,f.b),r[0].style.background=c=\"#\"+C(f),(l.match(/[0-9]{1,3}/g)||[]).length>3&&\"rgba\"===r.attr(\"lay-type\")){var u=280*l.slice(l.lastIndexOf(\",\")+1,l.length-1);e.elemPicker.find(\".\"+h).css(\"left\",u),r[0].style.background=l,c=l}}else f=y(l),r[0].style.background=c=\"#\"+C(f),e.elemColorBox.find(\".\"+d).removeClass(s).addClass(a);return\"change\"===n?(e.select(f.h,f.s,f.b,n),void(o.change&&o.change(c))):(e.color=l,o.done&&o.done(l),void e.removePicker())}};e.elemPicker.on(\"click\",\"*[colorpicker-events]\",function(){var e=i(this),o=e.attr(\"colorpicker-events\");n[o]&&n[o].call(this,e)}),t.on(\"keyup\",function(e){var o=i(this);n.confirm.call(this,o,13===e.keyCode?null:\"change\")})},D.prototype.events=function(){var e=this,o=e.config,r=e.elemColorBox.find(\".\"+f);e.elemColorBox.on(\"click\",function(){e.renderPicker(),i(c)[0]&&(e.val(),e.side())}),o.elem[0]&&!e.elemColorBox[0].eventHandler&&(w.on(\"click\",function(o){if(!i(o.target).hasClass(l)&&!i(o.target).parents(\".\"+l)[0]&&!i(o.target).hasClass(c.replace(/\\./g,\"\"))&&!i(o.target).parents(c)[0]&&e.elemPicker){if(e.color){var t=k(P(e.color));e.select(t.h,t.s,t.b)}else e.elemColorBox.find(\".\"+d).removeClass(a).addClass(s);r[0].style.background=e.color||\"\",e.removePicker()}}),B.on(\"resize\",function(){return!(!e.elemPicker||!i(c)[0])&&void e.position()}),e.elemColorBox[0].eventHandler=!0)},o.render=function(e){var i=new D(e);return r.call(i)},e(t,o)});layui.define(\"layer\",function(e){\"use strict\";var t=layui.$,i=layui.layer,a=layui.hint(),n=layui.device(),l=\"form\",r=\".layui-form\",s=\"layui-this\",o=\"layui-hide\",c=\"layui-disabled\",u=function(){this.config={verify:{required:[/[\\S]+/,\"必填项不能为空\"],phone:[/^1\\d{10}$/,\"请输入正确的手机号\"],email:[/^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$/,\"邮箱格式不正确\"],url:[/(^#)|(^http(s*):\\/\\/[^\\s]+\\.[^\\s]+)/,\"链接格式不正确\"],number:function(e){if(!e||isNaN(e))return\"只能填写数字\"},date:[/^(\\d{4})[-\\/](\\d{1}|0\\d{1}|1[0-2])([-\\/](\\d{1}|0\\d{1}|[1-2][0-9]|3[0-1]))*$/,\"日期格式不正确\"],identity:[/(^\\d{15}$)|(^\\d{17}(x|X|\\d)$)/,\"请输入正确的身份证号\"]}}};u.prototype.set=function(e){var i=this;return t.extend(!0,i.config,e),i},u.prototype.verify=function(e){var i=this;return t.extend(!0,i.config.verify,e),i},u.prototype.on=function(e,t){return layui.onevent.call(this,l,e,t)},u.prototype.val=function(e,i){var a=t(r+'[lay-filter=\"'+e+'\"]');a.each(function(e,a){var n=t(this);layui.each(i,function(e,t){var i,a=n.find('[name=\"'+e+'\"]');a[0]&&(i=a[0].type,\"checkbox\"===i?a[0].checked=t:\"radio\"===i?a.each(function(){this.value==t&&(this.checked=!0)}):a.val(t))})}),f.render(null,e)},u.prototype.render=function(e,i){var n=this,u=t(r+function(){return i?'[lay-filter=\"'+i+'\"]':\"\"}()),d={select:function(){var e,i=\"请选择\",a=\"layui-form-select\",n=\"layui-select-title\",r=\"layui-select-none\",d=\"\",f=u.find(\"select\"),v=function(i,l){t(i.target).parent().hasClass(n)&&!l||(t(\".\"+a).removeClass(a+\"ed \"+a+\"up\"),e&&d&&e.val(d)),e=null},y=function(i,u,f){var y,p=t(this),m=i.find(\".\"+n),k=m.find(\"input\"),x=i.find(\"dl\"),g=x.children(\"dd\"),b=this.selectedIndex;if(!u){var C=function(){var e=i.offset().top+i.outerHeight()+5-h.scrollTop(),t=x.outerHeight();b=p[0].selectedIndex,i.addClass(a+\"ed\"),g.removeClass(o),y=null,g.eq(b).addClass(s).siblings().removeClass(s),e+t>h.height()&&e>=t&&i.addClass(a+\"up\"),T()},w=function(e){i.removeClass(a+\"ed \"+a+\"up\"),k.blur(),y=null,e||$(k.val(),function(e){var i=p[0].selectedIndex;e&&(d=t(p[0].options[i]).html(),0===i&&d===k.attr(\"placeholder\")&&(d=\"\"),k.val(d||\"\"))})},T=function(){var e=x.children(\"dd.\"+s);if(e[0]){var t=e.position().top,i=x.height(),a=e.height();t>i&&x.scrollTop(t+x.scrollTop()-i+a-5),t<0&&x.scrollTop(t+x.scrollTop()-5)}};m.on(\"click\",function(e){i.hasClass(a+\"ed\")?w():(v(e,!0),C()),x.find(\".\"+r).remove()}),m.find(\".layui-edge\").on(\"click\",function(){k.focus()}),k.on(\"keyup\",function(e){var t=e.keyCode;9===t&&C()}).on(\"keydown\",function(e){var t=e.keyCode;9===t&&w();var i=function(t,a){var n,l;e.preventDefault();var r=function(){var e=x.children(\"dd.\"+s);if(x.children(\"dd.\"+o)[0]&&\"next\"===t){var i=x.children(\"dd:not(.\"+o+\",.\"+c+\")\"),n=i.eq(0).index();if(n>=0&&n<e.index()&&!i.hasClass(s))return i.eq(0).prev()[0]?i.eq(0).prev():x.children(\":last\")}return a&&a[0]?a:y&&y[0]?y:e}();return l=r[t](),n=r[t](\"dd:not(.\"+o+\")\"),l[0]?(y=r[t](),n[0]&&!n.hasClass(c)||!y[0]?(n.addClass(s).siblings().removeClass(s),void T()):i(t,y)):y=null};38===t&&i(\"prev\"),40===t&&i(\"next\"),13===t&&(e.preventDefault(),x.children(\"dd.\"+s).trigger(\"click\"))});var $=function(e,i,a){var n=0;layui.each(g,function(){var i=t(this),l=i.text(),r=l.indexOf(e)===-1;(\"\"===e||\"blur\"===a?e!==l:r)&&n++,\"keyup\"===a&&i[r?\"addClass\":\"removeClass\"](o)});var l=n===g.length;return i(l),l},q=function(e){var t=this.value,i=e.keyCode;return 9!==i&&13!==i&&37!==i&&38!==i&&39!==i&&40!==i&&($(t,function(e){e?x.find(\".\"+r)[0]||x.append('<p class=\"'+r+'\">无匹配项</p>'):x.find(\".\"+r).remove()},\"keyup\"),\"\"===t&&x.find(\".\"+r).remove(),void T())};f&&k.on(\"keyup\",q).on(\"blur\",function(i){var a=p[0].selectedIndex;e=k,d=t(p[0].options[a]).html(),0===a&&d===k.attr(\"placeholder\")&&(d=\"\"),setTimeout(function(){$(k.val(),function(e){d||k.val(\"\")},\"blur\")},200)}),g.on(\"click\",function(){var e=t(this),a=e.attr(\"lay-value\"),n=p.attr(\"lay-filter\");return!e.hasClass(c)&&(e.hasClass(\"layui-select-tips\")?k.val(\"\"):(k.val(e.text()),e.addClass(s)),e.siblings().removeClass(s),p.val(a).removeClass(\"layui-form-danger\"),layui.event.call(this,l,\"select(\"+n+\")\",{elem:p[0],value:a,othis:i}),w(!0),!1)}),i.find(\"dl>dt\").on(\"click\",function(e){return!1}),t(document).off(\"click\",v).on(\"click\",v)}};f.each(function(e,l){var r=t(this),o=r.next(\".\"+a),u=this.disabled,d=l.value,f=t(l.options[l.selectedIndex]),v=l.options[0];if(\"string\"==typeof r.attr(\"lay-ignore\"))return r.show();var h=\"string\"==typeof r.attr(\"lay-search\"),p=v?v.value?i:v.innerHTML||i:i,m=t(['<div class=\"'+(h?\"\":\"layui-unselect \")+a,(u?\" layui-select-disabled\":\"\")+'\">','<div class=\"'+n+'\">','<input type=\"text\" placeholder=\"'+p+'\" '+('value=\"'+(d?f.html():\"\")+'\"')+(h?\"\":\" readonly\")+' class=\"layui-input'+(h?\"\":\" layui-unselect\")+(u?\" \"+c:\"\")+'\">','<i class=\"layui-edge\"></i></div>','<dl class=\"layui-anim layui-anim-upbit'+(r.find(\"optgroup\")[0]?\" layui-select-group\":\"\")+'\">',function(e){var t=[];return layui.each(e,function(e,a){0!==e||a.value?\"optgroup\"===a.tagName.toLowerCase()?t.push(\"<dt>\"+a.label+\"</dt>\"):t.push('<dd lay-value=\"'+a.value+'\" class=\"'+(d===a.value?s:\"\")+(a.disabled?\" \"+c:\"\")+'\">'+a.innerHTML+\"</dd>\"):t.push('<dd lay-value=\"\" class=\"layui-select-tips\">'+(a.innerHTML||i)+\"</dd>\")}),0===t.length&&t.push('<dd lay-value=\"\" class=\"'+c+'\">没有选项</dd>'),t.join(\"\")}(r.find(\"*\"))+\"</dl>\",\"</div>\"].join(\"\"));o[0]&&o.remove(),r.after(m),y.call(this,m,u,h)})},checkbox:function(){var e={checkbox:[\"layui-form-checkbox\",\"layui-form-checked\",\"checkbox\"],_switch:[\"layui-form-switch\",\"layui-form-onswitch\",\"switch\"]},i=u.find(\"input[type=checkbox]\"),a=function(e,i){var a=t(this);e.on(\"click\",function(){var t=a.attr(\"lay-filter\"),n=(a.attr(\"lay-text\")||\"\").split(\"|\");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(i[1]).find(\"em\").text(n[1])):(a[0].checked=!0,e.addClass(i[1]).find(\"em\").text(n[0])),layui.event.call(a[0],l,i[2]+\"(\"+t+\")\",{elem:a[0],value:a[0].value,othis:e}))})};i.each(function(i,n){var l=t(this),r=l.attr(\"lay-skin\"),s=(l.attr(\"lay-text\")||\"\").split(\"|\"),o=this.disabled;\"switch\"===r&&(r=\"_\"+r);var u=e[r]||e.checkbox;if(\"string\"==typeof l.attr(\"lay-ignore\"))return l.show();var d=l.next(\".\"+u[0]),f=t(['<div class=\"layui-unselect '+u[0],n.checked?\" \"+u[1]:\"\",o?\" layui-checkbox-disbaled \"+c:\"\",'\"',r?' lay-skin=\"'+r+'\"':\"\",\">\",function(){var e=n.title.replace(/\\s/g,\"\"),t={checkbox:[e?\"<span>\"+n.title+\"</span>\":\"\",'<i class=\"layui-icon layui-icon-ok\"></i>'].join(\"\"),_switch:\"<em>\"+((n.checked?s[0]:s[1])||\"\")+\"</em><i></i>\"};return t[r]||t.checkbox}(),\"</div>\"].join(\"\"));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e=\"layui-form-radio\",i=[\"&#xe643;\",\"&#xe63f;\"],a=u.find(\"input[type=radio]\"),n=function(a){var n=t(this),s=\"layui-anim-scaleSpring\";a.on(\"click\",function(){var o=n[0].name,c=n.parents(r),u=n.attr(\"lay-filter\"),d=c.find(\"input[name=\"+o.replace(/(\\.|#|\\[|\\])/g,\"\\\\$1\")+\"]\");n[0].disabled||(layui.each(d,function(){var a=t(this).next(\".\"+e);this.checked=!1,a.removeClass(e+\"ed\"),a.find(\".layui-icon\").removeClass(s).html(i[1])}),n[0].checked=!0,a.addClass(e+\"ed\"),a.find(\".layui-icon\").addClass(s).html(i[0]),layui.event.call(n[0],l,\"radio(\"+u+\")\",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=t(this),s=r.next(\".\"+e),o=this.disabled;if(\"string\"==typeof r.attr(\"lay-ignore\"))return r.show();s[0]&&s.remove();var u=t(['<div class=\"layui-unselect '+e,l.checked?\" \"+e+\"ed\":\"\",(o?\" layui-radio-disbaled \"+c:\"\")+'\">','<i class=\"layui-anim layui-icon\">'+i[l.checked?0:1]+\"</i>\",\"<div>\"+function(){var e=l.title||\"\";return\"string\"==typeof r.next().attr(\"lay-radio\")&&(e=r.next().html(),r.next().remove()),e}()+\"</div>\",\"</div>\"].join(\"\"));r.after(u),n.call(this,u)})}};return e?d[e]?d[e]():a.error(\"不支持的\"+e+\"表单渲染\"):layui.each(d,function(e,t){t()}),n};var d=function(){var e=t(this),a=f.config.verify,s=null,o=\"layui-form-danger\",c={},u=e.parents(r),d=u.find(\"*[lay-verify]\"),v=e.parents(\"form\")[0],h=u.find(\"input,select,textarea\"),y=e.attr(\"lay-filter\");if(layui.each(d,function(e,l){var r=t(this),c=r.attr(\"lay-verify\").split(\"|\"),u=r.attr(\"lay-verType\"),d=r.val();if(r.removeClass(o),layui.each(c,function(e,t){var c,f=\"\",v=\"function\"==typeof a[t];if(a[t]){var c=v?f=a[t](d,l):!a[t][0].test(d);if(f=f||a[t][1],\"required\"===t&&(f=r.attr(\"lay-reqText\")||f),c)return\"tips\"===u?i.tips(f,function(){return\"string\"==typeof r.attr(\"lay-ignore\")||\"select\"!==l.tagName.toLowerCase()&&!/^checkbox|radio$/.test(l.type)?r:r.next()}(),{tips:1}):\"alert\"===u?i.alert(f,{title:\"提示\",shadeClose:!0}):i.msg(f,{icon:5,shift:6}),n.android||n.ios||setTimeout(function(){l.focus()},7),r.addClass(o),s=!0}}),s)return s}),s)return!1;var p={};return layui.each(h,function(e,t){if(t.name=(t.name||\"\").replace(/^\\s*|\\s*&/,\"\"),t.name){if(/^.*\\[\\]$/.test(t.name)){var i=t.name.match(/^(.*)\\[\\]$/g)[0];p[i]=0|p[i],t.name=t.name.replace(/^(.*)\\[\\]$/,\"$1[\"+p[i]++ +\"]\")}/^checkbox|radio$/.test(t.type)&&!t.checked||(c[t.name]=t.value)}}),layui.event.call(this,l,\"submit(\"+y+\")\",{elem:this,form:v,field:c})},f=new u,v=t(document),h=t(window);f.render(),v.on(\"reset\",r,function(){var e=t(this).attr(\"lay-filter\");setTimeout(function(){f.render(null,e)},50)}),v.on(\"submit\",r,d).on(\"click\",\"*[lay-submit]\",d),e(l,f)});layui.define(\"form\",function(e){\"use strict\";var i=layui.$,a=layui.form,n=\"tree\",r={config:{},index:layui[n]?layui[n].index+1e4:0,set:function(e){var a=this;return a.config=i.extend({},a.config,e),a},on:function(e,i){return layui.onevent.call(this,n,e,i)}},l=function(){var e=this,i=e.config,a=i.id||e.index;return l.that[a]=e,l.config[a]=i,{config:i,reload:function(i){e.reload.call(e,i)},getChecked:function(){return e.getChecked.call(e)},setChecked:function(i){return e.setChecked.call(e,i)}}},t=\"layui-hide\",d=\"layui-disabled\",s=\"layui-tree-set\",c=\"layui-tree-iconClick\",o=\"layui-icon-addition\",h=\"layui-icon-subtraction\",u=\"layui-tree-entry\",f=\"layui-tree-main\",p=\"layui-tree-txt\",y=\"layui-tree-pack\",v=\"layui-tree-spread\",C=\"layui-tree-setLineShort\",m=\"layui-tree-showLine\",k=\"layui-tree-lineExtend\",g=function(e){var a=this;a.index=++r.index,a.config=i.extend({},a.config,r.config,e),a.render()};g.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:\"未命名\",none:\"无数据\"}},g.prototype.reload=function(e){var a=this;layui.each(e,function(e,i){i.constructor===Array&&delete a.config[e]}),a.config=i.extend(!0,{},a.config,e),a.render()},g.prototype.render=function(){var e=this,a=e.config,n=i('<div class=\"layui-tree'+(a.showCheckbox?\" layui-form\":\"\")+(a.showLine?\" layui-tree-line\":\"\")+'\" lay-filter=\"LAY-tree-'+e.index+'\"></div>');e.tree(n);var r=a.elem=i(a.elem);if(r[0]){if(a.showSearch&&n.prepend('<input type=\"text\" class=\"layui-input layui-tree-search\" placeholder=\"请输入关键字进行过滤\">'),e.key=a.id||e.index,e.elem=n,e.elemNone=i('<div class=\"layui-tree-emptyText\">'+a.text.none+\"</div>\"),r.html(e.elem),0==e.elem.find(\".layui-tree-set\").length)return e.elem.append(e.elemNone);a.drag&&e.drag(),a.showCheckbox&&e.renderForm(\"checkbox\"),e.elem.find(\".layui-tree-set\").each(function(){var e=i(this);e.parent(\".layui-tree-pack\")[0]||e.addClass(\"layui-tree-setHide\"),!e.next()[0]&&e.parents(\".layui-tree-pack\").eq(1).hasClass(\"layui-tree-lineExtend\")&&e.addClass(C),e.next()[0]||e.parents(\".layui-tree-set\").eq(0).next()[0]||e.addClass(C)}),e.events()}},g.prototype.renderForm=function(e){a.render(e,\"LAY-tree-\"+this.index)},g.prototype.tree=function(e,a){var n=this,r=n.config,l=a||r.data;layui.each(l,function(a,l){var c=l.children&&l.children.length>0,o=i('<div class=\"layui-tree-pack\" '+(l.spread?'style=\"display: block;\"':\"\")+'\"></div>'),h=i(['<div data-id=\"'+l.id+'\" class=\"layui-tree-set'+(l.spread?\" layui-tree-spread\":\"\")+(l.checked?\" layui-tree-checkedFirst\":\"\")+'\">',\"<div \"+(r.drag&&!l.fixed?'draggable=\"true\"':\"\")+' class=\"layui-tree-entry\">','<div class=\"layui-tree-main\">',function(){return r.showLine?c?'<span class=\"layui-tree-iconClick layui-tree-icon\"><i class=\"layui-icon '+(l.spread?\"layui-icon-subtraction\":\"layui-icon-addition\")+'\"></i></span>':'<span class=\"layui-tree-iconClick\"><i class=\"layui-icon layui-icon-file\"></i></span>':'<span class=\"layui-tree-iconClick\"><i class=\"layui-tree-iconArrow '+(c?\"\":t)+'\"></i></span>'}(),function(){return r.showCheckbox?'<input type=\"checkbox\" name=\"layuiTreeCheck\" lay-skin=\"primary\" '+(l.disabled?\"disabled\":\"\")+'  value=\"'+l.id+'\">':\"\"}(),function(){return r.isJump&&l.href?'<a href=\"'+l.href+'\" target=\"_blank\" class=\"'+p+'\">'+(l.title||l.label||r.text.defaultNodeName)+\"</a>\":'<span class=\"'+p+(l.disabled?\" \"+d:\"\")+'\">'+(l.title||l.label||r.text.defaultNodeName)+\"</span>\"}(),\"</div>\",function(){if(!r.edit)return\"\";var e={add:'<i class=\"layui-icon layui-icon-add-1\"  data-type=\"add\"></i>',update:'<i class=\"layui-icon layui-icon-edit\" data-type=\"update\"></i>',del:'<i class=\"layui-icon layui-icon-delete\" data-type=\"del\"></i>'},i=['<div class=\"layui-btn-group layui-tree-btnGroup\">'];return r.edit===!0&&(r.edit=[\"update\",\"del\"]),\"object\"==typeof r.edit?(layui.each(r.edit,function(a,n){i.push(e[n]||\"\")}),i.join(\"\")+\"</div>\"):void 0}(),\"</div></div>\"].join(\"\"));c&&(h.append(o),n.tree(o,l.children)),e.append(h),h.prev(\".\"+s)[0]&&h.prev().children(\".layui-tree-pack\").addClass(\"layui-tree-showLine\"),c||h.parent(\".layui-tree-pack\").addClass(\"layui-tree-lineExtend\"),n.spread(h,l),r.showCheckbox&&n.checkClick(h,l),r.edit&&n.operate(h,l)})},g.prototype.spread=function(e,a){var n=this,r=n.config,l=e.children(\".\"+u),t=l.children(\".\"+f),C=l.find(\".\"+c),m=l.find(\".\"+p),k=r.onlyIconControl?C:t,g=\"\";k.on(\"click\",function(i){var a=e.children(\".\"+y),n=k.children(\".layui-icon\")[0]?k.children(\".layui-icon\"):k.find(\".layui-tree-icon\").children(\".layui-icon\");if(a[0]){if(e.hasClass(v))e.removeClass(v),a.slideUp(200),n.removeClass(h).addClass(o);else if(e.addClass(v),a.slideDown(200),n.addClass(h).removeClass(o),r.accordion){var l=e.siblings(\".\"+s);l.removeClass(v),l.children(\".\"+y).slideUp(200),l.find(\".layui-tree-icon\").children(\".layui-icon\").removeClass(h).addClass(o)}}else g=\"normal\"}),m.on(\"click\",function(){var n=i(this);n.hasClass(d)||(g=e.hasClass(v)?r.onlyIconControl?\"open\":\"close\":r.onlyIconControl?\"close\":\"open\",r.click&&r.click({elem:e,state:g,data:a}))})},g.prototype.setCheckbox=function(e,i,a){var n=this,r=(n.config,a.prop(\"checked\"));if(\"object\"==typeof i.children||e.find(\".\"+y)[0]){var l=e.find(\".\"+y).find('input[name=\"layuiTreeCheck\"]');l.each(function(){this.disabled||(this.checked=r)})}var t=function(e){if(e.parents(\".\"+s)[0]){var i,a=e.parent(\".\"+y),n=a.parent(),l=a.prev().find('input[name=\"layuiTreeCheck\"]');r?l.prop(\"checked\",r):(a.find('input[name=\"layuiTreeCheck\"]').each(function(){this.checked&&(i=!0)}),i||l.prop(\"checked\",!1)),t(n)}};t(e),n.renderForm(\"checkbox\")},g.prototype.checkClick=function(e,a){var n=this,r=n.config,l=e.children(\".\"+u),t=l.children(\".\"+f);t.on(\"click\",'input[name=\"layuiTreeCheck\"]+',function(l){layui.stope(l);var t=i(this).prev(),d=t.prop(\"checked\");t.prop(\"disabled\")||(n.setCheckbox(e,a,t),r.oncheck&&r.oncheck({elem:e,checked:d,data:a}))})},g.prototype.operate=function(e,a){var n=this,r=n.config,l=e.children(\".\"+u),d=l.children(\".\"+f);l.children(\".layui-tree-btnGroup\").on(\"click\",\".layui-icon\",function(l){layui.stope(l);var f=i(this).data(\"type\"),g=e.children(\".\"+y),x={data:a,type:f,elem:e};if(\"add\"==f){g[0]||(r.showLine?(d.find(\".\"+c).addClass(\"layui-tree-icon\"),d.find(\".\"+c).children(\".layui-icon\").addClass(o).removeClass(\"layui-icon-file\")):d.find(\".layui-tree-iconArrow\").removeClass(t),e.append('<div class=\"layui-tree-pack\"></div>'));var b=r.operate&&r.operate(x),w={};if(w.title=r.text.defaultNodeName,w.id=b,n.tree(e.children(\".\"+y),[w]),r.showLine)if(g[0])g.hasClass(k)||g.addClass(k),e.find(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)}),g.children(\".\"+s).last().prev().hasClass(C)?g.children(\".\"+s).last().prev().removeClass(C):g.children(\".\"+s).last().removeClass(C),!e.parent(\".\"+y)[0]&&e.next()[0]&&g.children(\".\"+s).last().removeClass(C);else{var T=e.siblings(\".\"+s),L=1,N=e.parent(\".\"+y);layui.each(T,function(e,a){i(a).children(\".\"+y)[0]||(L=0)}),1==L?(T.children(\".\"+y).addClass(m),T.children(\".\"+y).children(\".\"+s).removeClass(C),e.children(\".\"+y).addClass(m),N.removeClass(k),N.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C)):e.children(\".\"+y).children(\".\"+s).addClass(C)}if(!r.showCheckbox)return;if(d.find('input[name=\"layuiTreeCheck\"]')[0].checked){var A=e.children(\".\"+y).children(\".\"+s).last();A.find('input[name=\"layuiTreeCheck\"]')[0].checked=!0}n.renderForm(\"checkbox\")}else if(\"update\"==f){var q=d.children(\".\"+p).html();d.children(\".\"+p).html(\"\"),d.append('<input type=\"text\" class=\"layui-tree-editInput\">'),d.children(\".layui-tree-editInput\").val(q).focus();var F=function(e){var i=e.val().trim();i=i?i:r.text.defaultNodeName,e.remove(),d.children(\".\"+p).html(i),x.data.title=i,r.operate&&r.operate(x)};d.children(\".layui-tree-editInput\").blur(function(){F(i(this))}),d.children(\".layui-tree-editInput\").on(\"keydown\",function(e){13===e.keyCode&&(e.preventDefault(),F(i(this)))})}else{if(r.operate&&r.operate(x),x.status=\"remove\",!e.prev(\".\"+s)[0]&&!e.next(\".\"+s)[0]&&!e.parent(\".\"+y)[0])return e.remove(),void n.elem.append(n.elemNone);if(e.siblings(\".\"+s).children(\".\"+u)[0]){if(r.showCheckbox){var I=function(e){if(e.parents(\".\"+s)[0]){var a=e.siblings(\".\"+s).children(\".\"+u),r=e.parent(\".\"+y).prev(),l=r.find('input[name=\"layuiTreeCheck\"]')[0],t=1,d=0;0==l.checked&&(a.each(function(e,a){var n=i(a).find('input[name=\"layuiTreeCheck\"]')[0];0!=n.checked||n.disabled||(t=0),n.disabled||(d=1)}),1==t&&1==d&&(l.checked=!0,n.renderForm(\"checkbox\"),I(r.parent(\".\"+s))))}};I(e)}if(r.showLine){var T=e.siblings(\".\"+s),L=1,N=e.parent(\".\"+y);layui.each(T,function(e,a){i(a).children(\".\"+y)[0]||(L=0)}),1==L?(g[0]||(N.removeClass(k),T.children(\".\"+y).addClass(m),T.children(\".\"+y).children(\".\"+s).removeClass(C)),e.next()[0]?N.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C):e.prev().children(\".\"+y).children(\".\"+s).last().addClass(C),e.next()[0]||e.parents(\".\"+s)[1]||e.parents(\".\"+s).eq(0).next()[0]||e.prev(\".\"+s).addClass(C)):!e.next()[0]&&e.hasClass(C)&&e.prev().addClass(C)}}else{var H=e.parent(\".\"+y).prev();if(r.showLine){H.find(\".\"+c).removeClass(\"layui-tree-icon\"),H.find(\".\"+c).children(\".layui-icon\").removeClass(h).addClass(\"layui-icon-file\");var S=H.parents(\".\"+y).eq(0);S.addClass(k),S.children(\".\"+s).each(function(){i(this).children(\".\"+y).children(\".\"+s).last().addClass(C)})}else H.find(\".layui-tree-iconArrow\").addClass(t);e.parents(\".\"+s).eq(0).removeClass(v),e.parent(\".\"+y).remove()}e.remove()}})},g.prototype.drag=function(){var e=this,a=e.config;e.elem.on(\"dragstart\",\".\"+u,function(){var e=i(this).parent(\".\"+s),n=e.parents(\".\"+s)[0]?e.parents(\".\"+s).eq(0):\"未找到父节点\";a.dragstart&&a.dragstart(e,n)}),e.elem.on(\"dragend\",\".\"+u,function(n){var n=n||event,r=n.clientY,l=i(this),d=l.parent(\".\"+s),f=d.height(),p=d.offset().top,g=e.elem.find(\".\"+s),x=e.elem.height(),b=e.elem.offset().top,w=x+b-13,T=d.parents(\".\"+s)[0],L=d.next()[0];if(T)var N=d.parent(\".\"+y),A=d.parents(\".\"+s).eq(0),q=A.parent(\".\"+y),F=A.offset().top,I=d.siblings(),H=A.children(\".\"+y).children(\".\"+s).length;var S=function(n){if(T||L||e.elem.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C),!T)return void d.removeClass(\"layui-tree-setHide\");if(1==H)a.showLine?(n.find(\".\"+c).removeClass(\"layui-tree-icon\"),n.find(\".\"+c).children(\".layui-icon\").removeClass(h).addClass(\"layui-icon-file\"),q.addClass(k),q.children(\".\"+s).children(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)})):n.find(\".layui-tree-iconArrow\").addClass(t),n.children(\".\"+y).remove(),n.removeClass(v);else{if(a.showLine){var r=1;layui.each(I,function(e,a){i(a).children(\".\"+y)[0]||(r=0)}),1==r?(d.children(\".\"+y)[0]||(N.removeClass(k),I.children(\".\"+y).addClass(m),I.children(\".\"+y).children(\".\"+s).removeClass(C)),N.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C),L||n.parents(\".\"+s)[0]||n.next()[0]||N.children(\".\"+s).last().addClass(C)):!L&&d.hasClass(C)&&N.children(\".\"+s).last().addClass(C)}if(a.showCheckbox){var l=function(a){if(a){if(!a.parents(\".\"+s)[0])return}else if(!n[0])return;var r=a?a.siblings().children(\".\"+u):I.children(\".\"+u),t=a?a.parent(\".\"+y).prev():N.prev(),d=t.find('input[name=\"layuiTreeCheck\"]')[0],c=1,o=0;0==d.checked&&(r.each(function(e,a){var n=i(a).find('input[name=\"layuiTreeCheck\"]')[0];0!=n.checked||n.disabled||(c=0),n.disabled||(o=1)}),1==c&&1==o&&(d.checked=!0,e.renderForm(\"checkbox\"),l(t.parent(\".\"+s)||n)))};l()}}};g.each(function(){if(0!=i(this).height()){if(r>p&&r<p+f)return void(a.dragend&&a.dragend(\"drag error\"));if(1==H&&r>F&&r<p+f)return void(a.dragend&&a.dragend(\"drag error\"));var n=i(this).offset().top;if(r>n&&r<n+15){if(i(this).children(\".\"+y)[0]||(a.showLine?(i(this).find(\".\"+c).eq(0).addClass(\"layui-tree-icon\"),i(this).find(\".\"+c).eq(0).children(\".layui-icon\").addClass(o).removeClass(\"layui-icon-file\")):i(this).find(\".layui-tree-iconArrow\").removeClass(t),i(this).append('<div class=\"layui-tree-pack\"></div>')),i(this).children(\".\"+y).append(d),S(A),a.showLine){var l=i(this).children(\".\"+y).children(\".\"+s);if(d.children(\".\"+y).children(\".\"+s).last().addClass(C),1==l.length){var h=i(this).siblings(\".\"+s),v=1,g=i(this).parent(\".\"+y);layui.each(h,function(e,a){i(a).children(\".\"+y)[0]||(v=0)}),1==v?(h.children(\".\"+y).addClass(m),h.children(\".\"+y).children(\".\"+s).removeClass(C),i(this).children(\".\"+y).addClass(m),g.removeClass(k),g.children(\".\"+s).last().children(\".\"+y).children(\".\"+s).last().addClass(C).removeClass(\"layui-tree-setHide\")):i(this).children(\".\"+y).children(\".\"+s).addClass(C).removeClass(\"layui-tree-setHide\")}else d.prev(\".\"+s).hasClass(C)?(d.prev(\".\"+s).removeClass(C),d.addClass(C)):(d.removeClass(\"layui-tree-setLineShort layui-tree-setHide\"),d.children(\".\"+y)[0]?d.prev(\".\"+s).children(\".\"+y).children(\".\"+s).last().removeClass(C):d.siblings(\".\"+s).find(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)})),i(this).next()[0]||d.addClass(C)}if(a.showCheckbox&&i(this).children(\".\"+u).find('input[name=\"layuiTreeCheck\"]')[0].checked){var x=d.children(\".\"+u);x.find('input[name=\"layuiTreeCheck\"]+').click()}return a.dragend&&a.dragend(\"drag success\",d,i(this)),!1}if(r<n){if(i(this).before(d),S(A),a.showLine){var b=d.children(\".\"+y),T=i(this).parents(\".\"+s).eq(0),L=T.children(\".\"+y).children(\".\"+s).last();if(b[0]){d.removeClass(C),b.children(\".\"+s).last().removeClass(C);var h=d.siblings(\".\"+s),v=1;layui.each(h,function(e,a){i(a).children(\".\"+y)[0]||(v=0)}),1==v?T[0]&&(h.children(\".\"+y).addClass(m),h.children(\".\"+y).children(\".\"+s).removeClass(C),L.children(\".\"+y).children(\".\"+s).last().addClass(C).removeClass(m)):d.children(\".\"+y).children(\".\"+s).last().addClass(C),!T.parent(\".\"+y)[0]&&T.next()[0]&&L.removeClass(C)}else T.hasClass(k)||T.addClass(k),T.find(\".\"+y).each(function(){i(this).children(\".\"+s).last().addClass(C)});T[0]||(d.addClass(\"layui-tree-setHide\"),d.children(\".\"+y).children(\".\"+s).last().removeClass(C))}if(T[0]&&a.showCheckbox&&T.children(\".\"+u).find('input[name=\"layuiTreeCheck\"]')[0].checked){var x=d.children(\".\"+u);x.find('input[name=\"layuiTreeCheck\"]+').click()}return a.dragend&&a.dragend(\"拖拽成功，插入目标节点上方\",d,i(this)),!1}if(r>w)return e.elem.children(\".\"+s).last().children(\".\"+y).addClass(m),e.elem.append(d),S(A),d.prev().children(\".\"+y).children(\".\"+s).last().removeClass(C),d.addClass(\"layui-tree-setHide\"),d.children(\".\"+y).children(\".\"+s).last().addClass(C),a.dragend&&a.dragend(\"拖拽成功，插入最外层节点\",d,e.elem),!1}})})},g.prototype.events=function(){var e=this,a=e.config,n=e.elem.find(\".layui-tree-checkedFirst\");layui.each(n,function(e,a){i(a).children(\".\"+u).find('input[name=\"layuiTreeCheck\"]+').trigger(\"click\")}),e.elem.find(\".layui-tree-search\").on(\"keyup\",function(){var n=i(this),r=n.val(),l=n.nextAll(),d=[];l.find(\".\"+p).each(function(){var e=i(this).parents(\".\"+u);if(i(this).html().indexOf(r)!=-1){d.push(i(this).parent());var a=function(e){e.addClass(\"layui-tree-searchShow\"),e.parent(\".\"+y)[0]&&a(e.parent(\".\"+y).parent(\".\"+s))};a(e.parent(\".\"+s))}}),l.find(\".\"+u).each(function(){var e=i(this).parent(\".\"+s);e.hasClass(\"layui-tree-searchShow\")||e.addClass(t)}),0==l.find(\".layui-tree-searchShow\").length&&e.elem.append(e.elemNone),a.onsearch&&a.onsearch({elem:d})}),e.elem.find(\".layui-tree-search\").on(\"keydown\",function(){i(this).nextAll().find(\".\"+u).each(function(){var e=i(this).parent(\".\"+s);e.removeClass(\"layui-tree-searchShow \"+t)}),i(\".layui-tree-emptyText\")[0]&&i(\".layui-tree-emptyText\").remove()})},g.prototype.getChecked=function(){var e=this,a=e.config,n=[],r=[];e.elem.find(\".layui-form-checked\").each(function(){n.push(i(this).prev()[0].value)});var l=function(e,a){layui.each(e,function(e,r){layui.each(n,function(e,n){if(r.id==n){var t=i.extend({},r);return delete t.children,a.push(t),r.children&&(t.children=[],l(r.children,t.children)),!0}})})};return l(i.extend({},a.data),r),r},g.prototype.setChecked=function(e){var a=this;a.config;a.elem.find(\".\"+s).each(function(a,n){var r=i(this).data(\"id\"),l=i(n).children(\".\"+u).find('input[name=\"layuiTreeCheck\"]'),t=l.next();if(\"number\"==typeof e){if(r==e)return l[0].checked||t.click(),!1}else i.inArray(r,e)!=-1&&(l[0].checked||t.click())})},l.that={},l.config={},r.reload=function(e,i){var a=l.that[e];return a.reload(i),l.call(a)},r.getChecked=function(e){var i=l.that[e];return i.getChecked()},r.setChecked=function(e,i){var a=l.that[e];return a.setChecked(i)},r.render=function(e){var i=new g(e);return l.call(i)},e(n,r)});layui.define([\"laytpl\",\"form\"],function(e){\"use strict\";var a=layui.$,t=layui.laytpl,n=layui.form,i=\"transfer\",l={config:{},index:layui[i]?layui[i].index+1e4:0,set:function(e){var t=this;return t.config=a.extend({},t.config,e),t},on:function(e,a){return layui.onevent.call(this,i,e,a)}},r=function(){var e=this,a=e.config,t=a.id||e.index;return r.that[t]=e,r.config[t]=a,{config:a,reload:function(a){e.reload.call(e,a)},getData:function(){return e.getData.call(e)}}},c=\"layui-hide\",o=\"layui-btn-disabled\",d=\"layui-none\",s=\"layui-transfer-box\",u=\"layui-transfer-header\",h=\"layui-transfer-search\",f=\"layui-transfer-active\",y=\"layui-transfer-data\",p=function(e){return e=e||{},['<div class=\"layui-transfer-box\" data-index=\"'+e.index+'\">','<div class=\"layui-transfer-header\">','<input type=\"checkbox\" name=\"'+e.checkAllName+'\" lay-filter=\"layTransferCheckbox\" lay-type=\"all\" lay-skin=\"primary\" title=\"{{ d.data.title['+e.index+\"] || 'list\"+(e.index+1)+\"' }}\\\">\",\"</div>\",\"{{# if(d.data.showSearch){ }}\",'<div class=\"layui-transfer-search\">','<i class=\"layui-icon layui-icon-search\"></i>','<input type=\"input\" class=\"layui-input\" placeholder=\"关键词搜索\">',\"</div>\",\"{{# } }}\",'<ul class=\"layui-transfer-data\"></ul>',\"</div>\"].join(\"\")},v=['<div class=\"layui-transfer layui-form layui-border-box\" lay-filter=\"LAY-transfer-{{ d.index }}\">',p({index:0,checkAllName:\"layTransferLeftCheckAll\"}),'<div class=\"layui-transfer-active\">','<button type=\"button\" class=\"layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled\" data-index=\"0\">','<i class=\"layui-icon layui-icon-next\"></i>',\"</button>\",'<button type=\"button\" class=\"layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled\" data-index=\"1\">','<i class=\"layui-icon layui-icon-prev\"></i>',\"</button>\",\"</div>\",p({index:1,checkAllName:\"layTransferRightCheckAll\"}),\"</div>\"].join(\"\"),x=function(e){var t=this;t.index=++l.index,t.config=a.extend({},t.config,l.config,e),t.render()};x.prototype.config={title:[\"列表一\",\"列表二\"],width:200,height:360,data:[],value:[],showSearch:!1,id:\"\",text:{none:\"无数据\",searchNone:\"无匹配数据\"}},x.prototype.reload=function(e){var t=this;layui.each(e,function(e,a){a.constructor===Array&&delete t.config[e]}),t.config=a.extend(!0,{},t.config,e),t.render()},x.prototype.render=function(){var e=this,n=e.config,i=e.elem=a(t(v).render({data:n,index:e.index})),l=n.elem=a(n.elem);l[0]&&(n.data=n.data||[],n.value=n.value||[],e.key=n.id||e.index,l.html(e.elem),e.layBox=e.elem.find(\".\"+s),e.layHeader=e.elem.find(\".\"+u),e.laySearch=e.elem.find(\".\"+h),e.layData=i.find(\".\"+y),e.layBtn=i.find(\".\"+f+\" .layui-btn\"),e.layBox.css({width:n.width,height:n.height}),e.layData.css({height:function(){return n.height-e.layHeader.outerHeight()-e.laySearch.outerHeight()-2}()}),e.renderData(),e.events())},x.prototype.renderData=function(){var e=this,a=(e.config,[{checkName:\"layTransferLeftCheck\",views:[]},{checkName:\"layTransferRightCheck\",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,n=[\"<li>\",'<input type=\"checkbox\" name=\"'+a[t].checkName+'\" lay-skin=\"primary\" lay-filter=\"layTransferCheckbox\" title=\"'+e.title+'\"'+(e.disabled?\" disabled\":\"\")+(e.checked?\" checked\":\"\")+' value=\"'+e.value+'\">',\"</li>\"].join(\"\");a[t].views.push(n),delete e.selected}),e.layData.eq(0).html(a[0].views.join(\"\")),e.layData.eq(1).html(a[1].views.join(\"\")),e.renderCheckBtn()},x.prototype.renderForm=function(e){n.render(e,\"LAY-transfer-\"+this.index)},x.prototype.renderCheckBtn=function(e){var t=this,n=t.config;e=e||{},t.layBox.each(function(i){var l=a(this),r=l.find(\".\"+y),d=l.find(\".\"+u).find('input[type=\"checkbox\"]'),s=r.find('input[type=\"checkbox\"]'),h=0,f=!1;if(s.each(function(){var e=a(this).data(\"hide\");(this.checked||this.disabled||e)&&h++,this.checked&&!e&&(f=!0)}),d.prop(\"checked\",f&&h===s.length),t.layBtn.eq(i)[f?\"removeClass\":\"addClass\"](o),!e.stopNone){var p=r.children(\"li:not(.\"+c+\")\").length;t.noneView(r,p?\"\":n.text.none)}}),t.renderForm(\"checkbox\")},x.prototype.noneView=function(e,t){var n=a('<p class=\"layui-none\">'+(t||\"\")+\"</p>\");e.find(\".\"+d)[0]&&e.find(\".\"+d).remove(),t.replace(/\\s/g,\"\")&&e.append(n)},x.prototype.setValue=function(){var e=this,t=e.config,n=[];return e.layBox.eq(1).find(\".\"+y+' input[type=\"checkbox\"]').each(function(){var e=a(this).data(\"hide\");e||n.push(this.value)}),t.value=n,e},x.prototype.parseData=function(e){var t=this,n=t.config,i=[];return layui.each(n.data,function(t,l){l=(\"function\"==typeof n.parseData?n.parseData(l):l)||l,i.push(l=a.extend({},l)),layui.each(n.value,function(e,a){a==l.value&&(l.selected=!0)}),e&&e(l)}),n.data=i,t},x.prototype.getData=function(e){var a=this,t=a.config,n=[];return layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&n.push(t)})}),n},x.prototype.events=function(){var e=this,t=e.config;e.elem.on(\"click\",'input[lay-filter=\"layTransferCheckbox\"]+',function(){var t=a(this).prev(),n=t[0].checked,i=t.parents(\".\"+s).eq(0).find(\".\"+y);t[0].disabled||(\"all\"===t.attr(\"lay-type\")&&i.find('input[type=\"checkbox\"]').each(function(){this.disabled||(this.checked=n)}),e.renderCheckBtn({stopNone:!0}))}),e.layBtn.on(\"click\",function(){var n=a(this),i=n.data(\"index\"),l=e.layBox.eq(i),r=[];if(!n.hasClass(o)){e.layBox.eq(i).each(function(t){var n=a(this),i=n.find(\".\"+y);i.children(\"li\").each(function(){var t=a(this),n=t.find('input[type=\"checkbox\"]'),i=n.data(\"hide\");n[0].checked&&!i&&(n[0].checked=!1,l.siblings(\".\"+s).find(\".\"+y).append(t.clone()),t.remove(),r.push(n[0].value)),e.setValue()})}),e.renderCheckBtn();var c=l.siblings(\".\"+s).find(\".\"+h+\" input\");\"\"===c.val()||c.trigger(\"keyup\"),t.onchange&&t.onchange(e.getData(r),i)}}),e.laySearch.find(\"input\").on(\"keyup\",function(){var n=this.value,i=a(this).parents(\".\"+h).eq(0).siblings(\".\"+y),l=i.children(\"li\");l.each(function(){var e=a(this),t=e.find('input[type=\"checkbox\"]'),i=t[0].title.indexOf(n)!==-1;e[i?\"removeClass\":\"addClass\"](c),t.data(\"hide\",!i)}),e.renderCheckBtn();var r=l.length===i.children(\"li.\"+c).length;e.noneView(i,r?t.text.searchNone:\"\")})},r.that={},r.config={},l.reload=function(e,a){var t=r.that[e];return t.reload(a),r.call(t)},l.getData=function(e){var a=r.that[e];return a.getData()},l.render=function(e){var a=new x(e);return r.call(a)},e(i,l)});layui.define([\"laytpl\",\"laypage\",\"layer\",\"form\",\"util\"],function(e){\"use strict\";var t=layui.$,i=layui.laytpl,a=layui.laypage,l=layui.layer,n=layui.form,o=(layui.util,layui.hint()),r=layui.device(),d={config:{checkName:\"LAY_CHECKED\",indexName:\"LAY_TABLE_INDEX\"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,y,e,t)}},c=function(){var e=this,t=e.config,i=t.id||t.index;return i&&(c.that[i]=e,c.config[i]=t),{config:t,reload:function(t){e.reload.call(e,t)},setColsWidth:function(){e.setColsWidth.call(e)},resize:function(){e.resize.call(e)}}},s=function(e){var t=c.config[e];return t||o.error(\"The ID option was not found in the table instance\"),t||null},u=function(e,a,l,n){var o=e.templet?function(){return\"function\"==typeof e.templet?e.templet(l):i(t(e.templet).html()||String(a)).render(l)}():a;return n?t(\"<div>\"+o+\"</div>\").text():o},y=\"table\",h=\".layui-table\",f=\"layui-hide\",p=\"layui-none\",v=\"layui-table-view\",m=\".layui-table-tool\",g=\".layui-table-box\",b=\".layui-table-init\",x=\".layui-table-header\",k=\".layui-table-body\",C=\".layui-table-main\",w=\".layui-table-fixed\",T=\".layui-table-fixed-l\",A=\".layui-table-fixed-r\",L=\".layui-table-total\",N=\".layui-table-page\",S=\".layui-table-sort\",W=\"layui-table-edit\",_=\"layui-table-hover\",E=function(e){var t='{{#if(item2.colspan){}} colspan=\"{{item2.colspan}}\"{{#} if(item2.rowspan){}} rowspan=\"{{item2.rowspan}}\"{{#}}}';return e=e||{},['<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>',\"<thead>\",\"{{# layui.each(d.data.cols, function(i1, item1){ }}\",\"<tr>\",\"{{# layui.each(item1, function(i2, item2){ }}\",'{{# if(item2.fixed && item2.fixed !== \"right\"){ left = true; } }}','{{# if(item2.fixed === \"right\"){ right = true; } }}',function(){return e.fixed&&\"right\"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== \"right\"){ }}':\"right\"===e.fixed?'{{# if(item2.fixed === \"right\"){ }}':\"\"}(),\"{{# var isSort = !(item2.colGroup) && item2.sort; }}\",'<th data-field=\"{{ item2.field||i2 }}\" data-key=\"{{d.index}}-{{i1}}-{{i2}}\" {{# if( item2.parentKey){ }}data-parentkey=\"{{ item2.parentKey }}\"{{# } }} {{# if(item2.minWidth){ }}data-minwidth=\"{{item2.minWidth}}\"{{# } }} '+t+' {{# if(item2.unresize || item2.colGroup){ }}data-unresize=\"true\"{{# } }} class=\"{{# if(item2.hide){ }}layui-hide{{# } }}{{# if(isSort){ }} layui-unselect{{# } }}{{# if(!item2.field){ }} layui-table-col-special{{# } }}\">','<div class=\"layui-table-cell laytable-cell-',\"{{# if(item2.colGroup){ }}\",\"group\",\"{{# } else { }}\",\"{{d.index}}-{{i1}}-{{i2}}\",'{{# if(item2.type !== \"normal\"){ }}',\" laytable-cell-{{ item2.type }}\",\"{{# } }}\",\"{{# } }}\",'\" {{#if(item2.align){}}align=\"{{item2.align}}\"{{#}}}>','{{# if(item2.type === \"checkbox\"){ }}','<input type=\"checkbox\" name=\"layTableCheckbox\" lay-skin=\"primary\" lay-filter=\"layTableAllChoose\" {{# if(item2[d.data.checkName]){ }}checked{{# }; }}>',\"{{# } else { }}\",'<span>{{item2.title||\"\"}}</span>',\"{{# if(isSort){ }}\",'<span class=\"layui-table-sort layui-inline\"><i class=\"layui-edge layui-table-sort-asc\" title=\"升序\"></i><i class=\"layui-edge layui-table-sort-desc\" title=\"降序\"></i></span>',\"{{# } }}\",\"{{# } }}\",\"</div>\",\"</th>\",e.fixed?\"{{# }; }}\":\"\",\"{{# }); }}\",\"</tr>\",\"{{# }); }}\",\"</thead>\",\"</table>\"].join(\"\")},z=['<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>',\"<tbody></tbody>\",\"</table>\"].join(\"\"),H=['<div class=\"layui-form layui-border-box {{d.VIEW_CLASS}}\" lay-filter=\"LAY-table-{{d.index}}\" lay-id=\"{{ d.data.id }}\" style=\"{{# if(d.data.width){ }}width:{{d.data.width}}px;{{# } }} {{# if(d.data.height){ }}height:{{d.data.height}}px;{{# } }}\">',\"{{# if(d.data.toolbar){ }}\",'<div class=\"layui-table-tool\">','<div class=\"layui-table-tool-temp\"></div>','<div class=\"layui-table-tool-self\"></div>',\"</div>\",\"{{# } }}\",'<div class=\"layui-table-box\">',\"{{# if(d.data.loading){ }}\",'<div class=\"layui-table-init\" style=\"background-color: #fff;\">','<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop\"></i>',\"</div>\",\"{{# } }}\",\"{{# var left, right; }}\",'<div class=\"layui-table-header\">',E(),\"</div>\",'<div class=\"layui-table-body layui-table-main\">',z,\"</div>\",\"{{# if(left){ }}\",'<div class=\"layui-table-fixed layui-table-fixed-l\">','<div class=\"layui-table-header\">',E({fixed:!0}),\"</div>\",'<div class=\"layui-table-body\">',z,\"</div>\",\"</div>\",\"{{# }; }}\",\"{{# if(right){ }}\",'<div class=\"layui-table-fixed layui-table-fixed-r\">','<div class=\"layui-table-header\">',E({fixed:\"right\"}),'<div class=\"layui-table-mend\"></div>',\"</div>\",'<div class=\"layui-table-body\">',z,\"</div>\",\"</div>\",\"{{# }; }}\",\"</div>\",\"{{# if(d.data.totalRow){ }}\",'<div class=\"layui-table-total\">','<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>','<tbody><tr><td><div class=\"layui-table-cell\" style=\"visibility: hidden;\">Total</div></td></tr></tbody>',\"</table>\",\"</div>\",\"{{# } }}\",\"{{# if(d.data.page){ }}\",'<div class=\"layui-table-page\">','<div id=\"layui-table-page{{d.index}}\"></div>',\"</div>\",\"{{# } }}\",\"<style>\",\"{{# layui.each(d.data.cols, function(i1, item1){\",\"layui.each(item1, function(i2, item2){ }}\",\".laytable-cell-{{d.index}}-{{i1}}-{{i2}}{ \",\"{{# if(item2.width){ }}\",\"width: {{item2.width}}px;\",\"{{# } }}\",\" }\",\"{{# });\",\"}); }}\",\"</style>\",\"</div>\"].join(\"\"),R=t(window),F=t(document),I=function(e){var i=this;i.index=++d.index,i.config=t.extend({},i.config,d.config,e),i.render()};I.prototype.config={limit:10,loading:!0,cellMinWidth:60,defaultToolbar:[\"filter\",\"exports\",\"print\"],autoSort:!0,text:{none:\"无数据\"}},I.prototype.render=function(){var e=this,a=e.config;if(a.elem=t(a.elem),a.where=a.where||{},a.id=a.id||a.elem.attr(\"id\")||e.index,a.request=t.extend({pageName:\"page\",limitName:\"limit\"},a.request),a.response=t.extend({statusName:\"code\",statusCode:0,msgName:\"msg\",dataName:\"data\",countName:\"count\"},a.response),\"object\"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,e.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return e;a.height&&/^full-\\d+$/.test(a.height)&&(e.fullHeightGap=a.height.split(\"-\")[1],a.height=R.height()-e.fullHeightGap),e.setInit();var l=a.elem,n=l.next(\".\"+v),o=e.elem=t(i(H).render({VIEW_CLASS:v,data:a,index:e.index}));if(a.index=e.index,e.key=a.id||a.index,n[0]&&n.remove(),l.after(o),e.layTool=o.find(m),e.layBox=o.find(g),e.layHeader=o.find(x),e.layMain=o.find(C),e.layBody=o.find(k),e.layFixed=o.find(w),e.layFixLeft=o.find(T),e.layFixRight=o.find(A),e.layTotal=o.find(L),e.layPage=o.find(N),e.renderToolbar(),e.fullSize(),a.cols.length>1){var r=e.layFixed.find(x).find(\"th\");r.height(e.layHeader.height()-1-parseFloat(r.css(\"padding-top\"))-parseFloat(r.css(\"padding-bottom\")))}e.pullData(e.page),e.events()},I.prototype.initOpts=function(e){var t=this,i=(t.config,{checkbox:48,radio:48,space:15,numbers:40});e.checkbox&&(e.type=\"checkbox\"),e.space&&(e.type=\"space\"),e.type||(e.type=\"normal\"),\"normal\"!==e.type&&(e.unresize=!0,e.width=e.width||i[e.type])},I.prototype.setInit=function(e){var t=this,i=t.config;return i.clientWidth=i.width||function(){var e=function(t){var a,l;t=t||i.elem.parent(),a=t.width();try{l=\"none\"===t.css(\"display\")}catch(n){}return!t[0]||a&&!l?a:e(t.parent())};return e()}(),\"width\"===e?i.clientWidth:void layui.each(i.cols,function(e,a){layui.each(a,function(l,n){if(!n)return void a.splice(l,1);if(n.key=e+\"-\"+l,n.hide=n.hide||!1,n.colGroup||n.colspan>1){var o=0;layui.each(i.cols[e+1],function(t,i){i.HAS_PARENT||o>1&&o==n.colspan||(i.HAS_PARENT=!0,i.parentKey=e+\"-\"+l,o+=parseInt(i.colspan>1?i.colspan:1))}),n.colGroup=!0}t.initOpts(n)})})},I.prototype.renderToolbar=function(){var e=this,a=e.config,l=['<div class=\"layui-inline\" lay-event=\"add\"><i class=\"layui-icon layui-icon-add-1\"></i></div>','<div class=\"layui-inline\" lay-event=\"update\"><i class=\"layui-icon layui-icon-edit\"></i></div>','<div class=\"layui-inline\" lay-event=\"delete\"><i class=\"layui-icon layui-icon-delete\"></i></div>'].join(\"\"),n=e.layTool.find(\".layui-table-tool-temp\");if(\"default\"===a.toolbar)n.html(l);else if(\"string\"==typeof a.toolbar){var o=t(a.toolbar).html()||\"\";o&&n.html(i(o).render(a))}var r={filter:{title:\"筛选列\",layEvent:\"LAYTABLE_COLS\",icon:\"layui-icon-cols\"},exports:{title:\"导出\",layEvent:\"LAYTABLE_EXPORT\",icon:\"layui-icon-export\"},print:{title:\"打印\",layEvent:\"LAYTABLE_PRINT\",icon:\"layui-icon-print\"}},d=[];\"object\"==typeof a.defaultToolbar&&layui.each(a.defaultToolbar,function(e,t){var i=r[t];i&&d.push('<div class=\"layui-inline\" title=\"'+i.title+'\" lay-event=\"'+i.layEvent+'\"><i class=\"layui-icon '+i.icon+'\"></i></div>')}),e.layTool.find(\".layui-table-tool-self\").html(d.join(\"\"))},I.prototype.setParentCol=function(e,t){var i=this,a=i.config,l=i.layHeader.find('th[data-key=\"'+a.index+\"-\"+t+'\"]'),n=parseInt(l.attr(\"colspan\"))||0;if(l[0]){var o=t.split(\"-\"),r=a.cols[o[0]][o[1]];e?n--:n++,l.attr(\"colspan\",n),l[n<1?\"addClass\":\"removeClass\"](f),r.colspan=n,r.hide=n<1;var d=l.data(\"parentkey\");d&&i.setParentCol(e,d)}},I.prototype.setColsPatch=function(){var e=this,t=e.config;layui.each(t.cols,function(t,i){layui.each(i,function(t,i){i.hide&&e.setParentCol(i.hide,i.parentKey)})})},I.prototype.setColsWidth=function(){var e=this,t=e.config,i=0,a=0,l=0,n=0,o=e.setInit(\"width\");e.eachCols(function(e,t){t.hide||i++}),o=o-function(){return\"line\"===t.skin||\"nob\"===t.skin?2:i+1}()-e.getScrollWidth(e.layMain[0])-1;var r=function(e){layui.each(t.cols,function(i,r){layui.each(r,function(i,d){var c=0,s=d.minWidth||t.cellMinWidth;return d?void(d.colGroup||d.hide||(e?l&&l<s&&(a--,c=s):(c=d.width||0,/\\d+%$/.test(c)?(c=Math.floor(parseFloat(c)/100*o),c<s&&(c=s)):c||(d.width=c=0,a++)),d.hide&&(c=0),n+=c)):void r.splice(i,1)})}),o>n&&a&&(l=(o-n)/a)};r(),r(!0),e.autoColNums=a,e.eachCols(function(i,a){var n=a.minWidth||t.cellMinWidth;a.colGroup||a.hide||(0===a.width?e.getCssRule(t.index+\"-\"+a.key,function(e){e.style.width=Math.floor(l>=n?l:n)+\"px\"}):/\\d+%$/.test(a.width)&&e.getCssRule(t.index+\"-\"+a.key,function(e){e.style.width=Math.floor(parseFloat(a.width)/100*o)+\"px\"}))});var d=e.layMain.width()-e.getScrollWidth(e.layMain[0])-e.layMain.children(\"table\").outerWidth();if(e.autoColNums&&d>=-i&&d<=i){var c=function(t){var i;return t=t||e.layHeader.eq(0).find(\"thead th:last-child\"),i=t.data(\"field\"),!i&&t.prev()[0]?c(t.prev()):t},s=c(),u=s.data(\"key\");e.getCssRule(u,function(t){var i=t.style.width||s.outerWidth();t.style.width=parseFloat(i)+d+\"px\",e.layMain.height()-e.layMain.prop(\"clientHeight\")>0&&(t.style.width=parseFloat(t.style.width)-1+\"px\")})}e.loading(!0)},I.prototype.resize=function(){var e=this;e.fullSize(),e.setColsWidth(),e.scrollPatch()},I.prototype.reload=function(e){var i=this;e=e||{},delete i.haveInit,e.data&&e.data.constructor===Array&&delete i.config.data,i.config=t.extend(!0,{},i.config,e),i.render()},I.prototype.errorView=function(e){var i=this,a=i.layMain.find(\".\"+p),l=t('<div class=\"'+p+'\">'+(e||\"Error\")+\"</div>\");a[0]&&(i.layNone.remove(),a.remove()),i.layFixed.addClass(f),i.layMain.find(\"tbody\").html(\"\"),i.layMain.append(i.layNone=l),d.cache[i.key]=[]},I.prototype.page=1,I.prototype.pullData=function(e){var i=this,a=i.config,l=a.request,n=a.response,o=function(){\"object\"==typeof a.initSort&&i.sort(a.initSort.field,a.initSort.type)};if(i.startTime=(new Date).getTime(),a.url){var r={};r[l.pageName]=e,r[l.limitName]=a.limit;var d=t.extend(r,a.where);a.contentType&&0==a.contentType.indexOf(\"application/json\")&&(d=JSON.stringify(d)),i.loading(),t.ajax({type:a.method||\"get\",url:a.url,contentType:a.contentType,data:d,dataType:\"json\",headers:a.headers||{},success:function(t){\"function\"==typeof a.parseData&&(t=a.parseData(t)||t),t[n.statusName]!=n.statusCode?(i.renderForm(),i.errorView(t[n.msgName]||'返回的数据不符合规范，正确的成功状态码应为：\"'+n.statusName+'\": '+n.statusCode)):(i.renderData(t,e,t[n.countName]),o(),a.time=(new Date).getTime()-i.startTime+\" ms\"),i.setColsWidth(),\"function\"==typeof a.done&&a.done(t,e,t[n.countName])},error:function(e,t){i.errorView(\"数据接口请求异常：\"+t),i.renderForm(),i.setColsWidth()}})}else if(a.data&&a.data.constructor===Array){var c={},s=e*a.limit-a.limit;c[n.dataName]=a.data.concat().splice(s,a.limit),c[n.countName]=a.data.length,i.renderData(c,e,c[n.countName]),o(),i.setColsWidth(),\"function\"==typeof a.done&&a.done(c,e,c[n.countName])}},I.prototype.eachCols=function(e){var t=this;return d.eachCols(null,e,t.config.cols),t},I.prototype.renderData=function(e,n,o,r){var c=this,s=c.config,y=e[s.response.dataName]||[],h=[],v=[],m=[],g=function(){var e;return!r&&c.sortKey?c.sort(c.sortKey.field,c.sortKey.sort,!0):(layui.each(y,function(a,l){var o=[],y=[],p=[],g=a+s.limit*(n-1)+1;0!==l.length&&(r||(l[d.config.indexName]=a),c.eachCols(function(n,r){var c=r.field||n,h=s.index+\"-\"+r.key,v=l[c];if(void 0!==v&&null!==v||(v=\"\"),!r.colGroup){var m=['<td data-field=\"'+c+'\" data-key=\"'+h+'\" '+function(){var e=[];return r.edit&&e.push('data-edit=\"'+r.edit+'\"'),r.align&&e.push('align=\"'+r.align+'\"'),r.templet&&e.push('data-content=\"'+v+'\"'),r.toolbar&&e.push('data-off=\"true\"'),r.event&&e.push('lay-event=\"'+r.event+'\"'),r.style&&e.push('style=\"'+r.style+'\"'),r.minWidth&&e.push('data-minwidth=\"'+r.minWidth+'\"'),e.join(\" \")}()+' class=\"'+function(){var e=[];return r.hide&&e.push(f),r.field||e.push(\"layui-table-col-special\"),e.join(\" \")}()+'\">','<div class=\"layui-table-cell laytable-cell-'+function(){return\"normal\"===r.type?h:h+\" laytable-cell-\"+r.type}()+'\">'+function(){var n=t.extend(!0,{LAY_INDEX:g},l),o=d.config.checkName;switch(r.type){case\"checkbox\":return'<input type=\"checkbox\" name=\"layTableCheckbox\" lay-skin=\"primary\" '+function(){return r[o]?(l[o]=r[o],r[o]?\"checked\":\"\"):n[o]?\"checked\":\"\"}()+\">\";case\"radio\":return n[o]&&(e=a),'<input type=\"radio\" name=\"layTableRadio_'+s.index+'\" '+(n[o]?\"checked\":\"\")+' lay-type=\"layTableRadio\">';case\"numbers\":return g}return r.toolbar?i(t(r.toolbar).html()||\"\").render(n):u(r,v,n)}(),\"</div></td>\"].join(\"\");o.push(m),r.fixed&&\"right\"!==r.fixed&&y.push(m),\"right\"===r.fixed&&p.push(m)}}),h.push('<tr data-index=\"'+a+'\">'+o.join(\"\")+\"</tr>\"),v.push('<tr data-index=\"'+a+'\">'+y.join(\"\")+\"</tr>\"),m.push('<tr data-index=\"'+a+'\">'+p.join(\"\")+\"</tr>\"))}),c.layBody.scrollTop(0),c.layMain.find(\".\"+p).remove(),c.layMain.find(\"tbody\").html(h.join(\"\")),c.layFixLeft.find(\"tbody\").html(v.join(\"\")),c.layFixRight.find(\"tbody\").html(m.join(\"\")),c.renderForm(),\"number\"==typeof e&&c.setThisRowChecked(e),c.syncCheckAll(),c.haveInit?c.scrollPatch():setTimeout(function(){c.scrollPatch()},50),c.haveInit=!0,l.close(c.tipsIndex),s.HAS_SET_COLS_PATCH||c.setColsPatch(),void(s.HAS_SET_COLS_PATCH=!0))};return d.cache[c.key]=y,c.layPage[0==o||0===y.length&&1==n?\"addClass\":\"removeClass\"](f),r?g():0===y.length?(c.renderForm(),c.errorView(s.text.none)):(c.layFixed.removeClass(f),g(),c.renderTotal(y),void(s.page&&(s.page=t.extend({elem:\"layui-table-page\"+s.index,count:o,limit:s.limit,limits:s.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:[\"prev\",\"page\",\"next\",\"skip\",\"count\",\"limit\"],prev:'<i class=\"layui-icon\">&#xe603;</i>',next:'<i class=\"layui-icon\">&#xe602;</i>',jump:function(e,t){t||(c.page=e.curr,s.limit=e.limit,c.pullData(e.curr))}},s.page),s.page.count=o,a.render(s.page))))},I.prototype.renderTotal=function(e){var t=this,i=t.config,a={};if(i.totalRow){layui.each(e,function(e,i){0!==i.length&&t.eachCols(function(e,t){var l=t.field||e,n=i[l];t.totalRow&&(a[l]=(a[l]||0)+(parseFloat(n)||0))})});var l=[];t.eachCols(function(e,t){var n=t.field||e,o=['<td data-field=\"'+n+'\" data-key=\"'+i.index+\"-\"+t.key+'\" '+function(){var e=[];return t.align&&e.push('align=\"'+t.align+'\"'),t.style&&e.push('style=\"'+t.style+'\"'),t.minWidth&&e.push('data-minwidth=\"'+t.minWidth+'\"'),e.join(\" \")}()+' class=\"'+function(){var e=[];return t.hide&&e.push(f),t.field||e.push(\"layui-table-col-special\"),e.join(\" \")}()+'\">','<div class=\"layui-table-cell laytable-cell-'+function(){var e=i.index+\"-\"+t.key;return\"normal\"===t.type?e:e+\" laytable-cell-\"+t.type}()+'\">'+function(){var e=t.totalRowText||\"\";return t.totalRow?parseFloat(a[n]).toFixed(2)||e:e}(),\"</div></td>\"].join(\"\");l.push(o)}),t.layTotal.find(\"tbody\").html(\"<tr>\"+l.join(\"\")+\"</tr>\")}},I.prototype.getColElem=function(e,t){var i=this,a=i.config;return e.eq(0).find(\".laytable-cell-\"+(a.index+\"-\"+t)+\":eq(0)\")},I.prototype.renderForm=function(e){n.render(e,\"LAY-table-\"+this.index)},I.prototype.setThisRowChecked=function(e){var t=this,i=(t.config,\"layui-table-click\"),a=t.layBody.find('tr[data-index=\"'+e+'\"]');a.addClass(i).siblings(\"tr\").removeClass(i)},I.prototype.sort=function(e,i,a,l){var n,r,c=this,s={},u=c.config,h=u.elem.attr(\"lay-filter\"),f=d.cache[c.key];\"string\"==typeof e&&c.layHeader.find(\"th\").each(function(i,a){var l=t(this),o=l.data(\"field\");if(o===e)return e=l,n=o,!1});try{var n=n||e.data(\"field\"),p=e.data(\"key\");if(c.sortKey&&!a&&n===c.sortKey.field&&i===c.sortKey.sort)return;var v=c.layHeader.find(\"th .laytable-cell-\"+p).find(S);c.layHeader.find(\"th\").find(S).removeAttr(\"lay-sort\"),v.attr(\"lay-sort\",i||null),c.layFixed.find(\"th\")}catch(m){return o.error(\"Table modules: Did not match to field\")}c.sortKey={field:n,sort:i},u.autoSort&&(\"asc\"===i?r=layui.sort(f,n):\"desc\"===i?r=layui.sort(f,n,!0):(r=layui.sort(f,d.config.indexName),delete c.sortKey)),s[u.response.dataName]=r||f,c.renderData(s,c.page,c.count,!0),l&&layui.event.call(e,y,\"sort(\"+h+\")\",{field:n,type:i})},I.prototype.loading=function(e){var i=this,a=i.config;a.loading&&(e?(i.layInit&&i.layInit.remove(),delete i.layInit,i.layBox.find(b).remove()):(i.layInit=t(['<div class=\"layui-table-init\">','<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop\"></i>',\"</div>\"].join(\"\")),i.layBox.append(i.layInit)))},I.prototype.setCheckData=function(e,t){var i=this,a=i.config,l=d.cache[i.key];l[e]&&l[e].constructor!==Array&&(l[e][a.checkName]=t)},I.prototype.syncCheckAll=function(){var e=this,t=e.config,i=e.layHeader.find('input[name=\"layTableCheckbox\"]'),a=function(i){return e.eachCols(function(e,a){\"checkbox\"===a.type&&(a[t.checkName]=i)}),i};i[0]&&(d.checkStatus(e.key).isAll?(i[0].checked||(i.prop(\"checked\",!0),e.renderForm(\"checkbox\")),a(!0)):(i[0].checked&&(i.prop(\"checked\",!1),e.renderForm(\"checkbox\")),a(!1)))},I.prototype.getCssRule=function(e,t){var i=this,a=i.elem.find(\"style\")[0],l=a.sheet||a.styleSheet||{},n=l.cssRules||l.rules;layui.each(n,function(i,a){if(a.selectorText===\".laytable-cell-\"+e)return t(a),!0})},I.prototype.fullSize=function(){var e,t=this,i=t.config,a=i.height;t.fullHeightGap&&(a=R.height()-t.fullHeightGap,a<135&&(a=135),t.elem.css(\"height\",a)),a&&(e=parseFloat(a)-(t.layHeader.outerHeight()||38),i.toolbar&&(e-=t.layTool.outerHeight()||50),i.totalRow&&(e-=t.layTotal.outerHeight()||40),i.page&&(e-=t.layPage.outerHeight()||41),t.layMain.css(\"height\",e-2))},I.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:(e=document.createElement(\"div\"),e.style.width=\"100px\",e.style.height=\"100px\",e.style.overflowY=\"scroll\",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},I.prototype.scrollPatch=function(){var e=this,i=e.layMain.children(\"table\"),a=e.layMain.width()-e.layMain.prop(\"clientWidth\"),l=e.layMain.height()-e.layMain.prop(\"clientHeight\"),n=(e.getScrollWidth(e.layMain[0]),i.outerWidth()-e.layMain.width()),o=function(e){if(a&&l){if(e=e.eq(0),!e.find(\".layui-table-patch\")[0]){var i=t('<th class=\"layui-table-patch\"><div class=\"layui-table-cell\"></div></th>');i.find(\"div\").css({width:a}),e.find(\"tr\").append(i)}}else e.find(\".layui-table-patch\").remove()};o(e.layHeader),o(e.layTotal);var r=e.layMain.height(),d=r-l;e.layFixed.find(k).css(\"height\",i.height()>=d?d:\"auto\"),e.layFixRight[n>0?\"removeClass\":\"addClass\"](f),e.layFixRight.css(\"right\",a-1)},I.prototype.events=function(){var e,a=this,o=a.config,c=t(\"body\"),s={},u=a.layHeader.find(\"th\"),h=\".layui-table-cell\",p=o.elem.attr(\"lay-filter\");a.layTool.on(\"click\",\"*[lay-event]\",function(e){var i=t(this),c=i.attr(\"lay-event\"),s=function(e){var l=t(e.list),n=t('<ul class=\"layui-table-tool-panel\"></ul>');n.html(l),o.height&&n.css(\"max-height\",o.height-(a.layTool.outerHeight()||50)),i.find(\".layui-table-tool-panel\")[0]||i.append(n),a.renderForm(),n.on(\"click\",function(e){layui.stope(e)}),e.done&&e.done(n,l)};switch(layui.stope(e),F.trigger(\"table.tool.panel.remove\"),l.close(a.tipsIndex),c){case\"LAYTABLE_COLS\":s({list:function(){var e=[];return a.eachCols(function(t,i){i.field&&\"normal\"==i.type&&e.push('<li><input type=\"checkbox\" name=\"'+i.field+'\" data-key=\"'+i.key+'\" data-parentkey=\"'+(i.parentKey||\"\")+'\" lay-skin=\"primary\" '+(i.hide?\"\":\"checked\")+' title=\"'+(i.title||i.field)+'\" lay-filter=\"LAY_TABLE_TOOL_COLS\"></li>')}),e.join(\"\")}(),done:function(){n.on(\"checkbox(LAY_TABLE_TOOL_COLS)\",function(e){var i=t(e.elem),l=this.checked,n=i.data(\"key\"),r=i.data(\"parentkey\");layui.each(o.cols,function(e,t){layui.each(t,function(t,i){if(e+\"-\"+t===n){var d=i.hide;i.hide=!l,a.elem.find('*[data-key=\"'+o.index+\"-\"+n+'\"]')[l?\"removeClass\":\"addClass\"](f),d!=i.hide&&a.setParentCol(!l,r),a.resize()}})})})}});break;case\"LAYTABLE_EXPORT\":r.ie?l.tips(\"导出功能不支持 IE，请用 Chrome 等高级浏览器导出\",this,{tips:3}):s({list:function(){return['<li data-type=\"csv\">导出到 Csv 文件</li>','<li data-type=\"xls\">导出到 Excel 文件</li>'].join(\"\")}(),done:function(e,i){i.on(\"click\",function(){var e=t(this).data(\"type\");d.exportFile(o.id,null,e)})}});break;case\"LAYTABLE_PRINT\":var u=window.open(\"打印窗口\",\"_blank\"),h=[\"<style>\",\"body{font-size: 12px; color: #666;}\",\"table{width: 100%; border-collapse: collapse; border-spacing: 0;}\",\"th,td{line-height: 20px; padding: 9px 15px; border: 1px solid #ccc; text-align: left; font-size: 12px; color: #666;}\",\"a{color: #666; text-decoration:none;}\",\"*.layui-hide{display: none}\",\"</style>\"].join(\"\"),v=t(a.layHeader.html());v.append(a.layMain.find(\"table\").html()),v.append(a.layTotal.find(\"table\").html()),v.find(\"th.layui-table-patch\").remove(),v.find(\".layui-table-col-special\").remove(),u.document.write(h+v.prop(\"outerHTML\")),u.document.close(),u.print(),u.close()}layui.event.call(this,y,\"toolbar(\"+p+\")\",t.extend({event:c,config:o},{}))}),u.on(\"mousemove\",function(e){var i=t(this),a=i.offset().left,l=e.clientX-a;i.data(\"unresize\")||s.resizeStart||(s.allowResize=i.width()-l<=10,c.css(\"cursor\",s.allowResize?\"col-resize\":\"\"))}).on(\"mouseleave\",function(){t(this);s.resizeStart||c.css(\"cursor\",\"\")}).on(\"mousedown\",function(e){var i=t(this);if(s.allowResize){var l=i.data(\"key\");e.preventDefault(),s.resizeStart=!0,s.offset=[e.clientX,e.clientY],a.getCssRule(l,function(e){var t=e.style.width||i.outerWidth();s.rule=e,s.ruleWidth=parseFloat(t),s.minWidth=i.data(\"minwidth\")||o.cellMinWidth})}}),F.on(\"mousemove\",function(t){if(s.resizeStart){if(t.preventDefault(),s.rule){var i=s.ruleWidth+t.clientX-s.offset[0];i<s.minWidth&&(i=s.minWidth),s.rule.style.width=i+\"px\",l.close(a.tipsIndex)}e=1}}).on(\"mouseup\",function(t){s.resizeStart&&(s={},c.css(\"cursor\",\"\"),a.scrollPatch()),2===e&&(e=null)}),u.on(\"click\",function(i){var l,n=t(this),o=n.find(S),r=o.attr(\"lay-sort\");return o[0]&&1!==e?(l=\"asc\"===r?\"desc\":\"desc\"===r?null:\"asc\",void a.sort(n,l,null,!0)):e=2}).find(S+\" .layui-edge \").on(\"click\",function(e){var i=t(this),l=i.index(),n=i.parents(\"th\").eq(0).data(\"field\");layui.stope(e),0===l?a.sort(n,\"asc\",null,!0):a.sort(n,\"desc\",null,!0)});var v=function(e){var l=t(this),n=l.parents(\"tr\").eq(0).data(\"index\"),o=a.layBody.find('tr[data-index=\"'+n+'\"]'),r=d.cache[a.key]||[];return r=r[n]||{},t.extend({tr:o,data:d.clearCacheKey(r),del:function(){d.cache[a.key][n]=[],o.remove(),a.scrollPatch()},update:function(e){e=e||{},layui.each(e,function(e,l){if(e in r){var n,d=o.children('td[data-field=\"'+e+'\"]');r[e]=l,a.eachCols(function(t,i){i.field==e&&i.templet&&(n=i.templet)}),d.children(h).html(function(){return n?function(){return\"function\"==typeof n?n(r):i(t(n).html()||l).render(r)}():l}()),d.data(\"content\",l)}})}},e)};a.elem.on(\"click\",'input[name=\"layTableCheckbox\"]+',function(){var e=t(this).prev(),i=a.layBody.find('input[name=\"layTableCheckbox\"]'),l=e.parents(\"tr\").eq(0).data(\"index\"),n=e[0].checked,o=\"layTableAllChoose\"===e.attr(\"lay-filter\");o?(i.each(function(e,t){t.checked=n,a.setCheckData(e,n)}),a.syncCheckAll(),a.renderForm(\"checkbox\")):(a.setCheckData(l,n),a.syncCheckAll()),layui.event.call(e[0],y,\"checkbox(\"+p+\")\",v.call(e[0],{checked:n,type:o?\"all\":\"one\"}))}),a.elem.on(\"click\",'input[lay-type=\"layTableRadio\"]+',function(){var e=t(this).prev(),i=e[0].checked,l=d.cache[a.key],n=e.parents(\"tr\").eq(0).data(\"index\");layui.each(l,function(e,t){n===e?t.LAY_CHECKED=!0:delete t.LAY_CHECKED}),a.setThisRowChecked(n),layui.event.call(this,y,\"radio(\"+p+\")\",v.call(this,{checked:i}))}),a.layBody.on(\"mouseenter\",\"tr\",function(){var e=t(this),i=e.index();e.data(\"off\")||a.layBody.find(\"tr:eq(\"+i+\")\").addClass(_)}).on(\"mouseleave\",\"tr\",function(){var e=t(this),i=e.index();e.data(\"off\")||a.layBody.find(\"tr:eq(\"+i+\")\").removeClass(_)}).on(\"click\",\"tr\",function(){m.call(this,\"row\")}).on(\"dblclick\",\"tr\",function(){m.call(this,\"rowDouble\")});var m=function(e){var i=t(this);i.data(\"off\")||layui.event.call(this,y,e+\"(\"+p+\")\",v.call(i.children(\"td\")[0]))};a.layBody.on(\"change\",\".\"+W,function(){var e=t(this),i=this.value,l=e.parent().data(\"field\"),n=e.parents(\"tr\").eq(0).data(\"index\"),o=d.cache[a.key][n];o[l]=i,layui.event.call(this,y,\"edit(\"+p+\")\",v.call(this,{value:i,field:l}))}).on(\"blur\",\".\"+W,function(){var e,l=t(this),n=this,o=l.parent().data(\"field\"),r=l.parents(\"tr\").eq(0).data(\"index\"),c=d.cache[a.key][r];a.eachCols(function(t,i){i.field==o&&i.templet&&(e=i.templet)}),l.siblings(h).html(function(a){return e?function(){return\"function\"==typeof e?e(c):i(t(e).html()||n.value).render(c)}():a}(n.value)),l.parent().data(\"content\",n.value),l.remove()}),a.layBody.on(\"click\",\"td\",function(e){var i=t(this),a=(i.data(\"field\"),i.data(\"edit\")),l=i.children(h);if(!i.data(\"off\")&&a){var n=t('<input class=\"layui-input '+W+'\">');return n[0].value=i.data(\"content\")||l.text(),i.find(\".\"+W)[0]||i.append(n),n.focus(),void layui.stope(e)}}).on(\"mouseenter\",\"td\",function(){b.call(this)}).on(\"mouseleave\",\"td\",function(){b.call(this,\"hide\")});var g=\"layui-table-grid-down\",b=function(e){var i=t(this),a=i.children(h);if(!i.data(\"off\"))if(e)i.find(\".layui-table-grid-down\").remove();else if(a.prop(\"scrollWidth\")>a.outerWidth()){if(a.find(\".\"+g)[0])return;i.append('<div class=\"'+g+'\"><i class=\"layui-icon layui-icon-down\"></i></div>')}};a.layBody.on(\"click\",\".\"+g,function(e){var i=t(this),n=i.parent(),d=n.children(h);a.tipsIndex=l.tips(['<div class=\"layui-table-tips-main\" style=\"margin-top: -'+(d.height()+16)+\"px;\"+function(){return\"sm\"===o.size?\"padding: 4px 15px; font-size: 12px;\":\"lg\"===o.size?\"padding: 14px 15px;\":\"\"}()+'\">',d.html(),\"</div>\",'<i class=\"layui-icon layui-table-tips-c layui-icon-close\"></i>'].join(\"\"),d[0],{tips:[3,\"\"],time:-1,anim:-1,maxWidth:r.ios||r.android?300:a.elem.width()/2,isOutAnim:!1,skin:\"layui-table-tips\",success:function(e,t){e.find(\".layui-table-tips-c\").on(\"click\",function(){l.close(t)})}}),layui.stope(e)}),a.layBody.on(\"click\",\"*[lay-event]\",function(){var e=t(this),i=e.parents(\"tr\").eq(0).data(\"index\");layui.event.call(this,y,\"tool(\"+p+\")\",v.call(this,{event:e.attr(\"lay-event\")})),a.setThisRowChecked(i)}),a.layMain.on(\"scroll\",function(){var e=t(this),i=e.scrollLeft(),n=e.scrollTop();a.layHeader.scrollLeft(i),a.layTotal.scrollLeft(i),a.layFixed.find(k).scrollTop(n),l.close(a.tipsIndex)}),F.on(\"click\",function(){F.trigger(\"table.remove.tool.panel\")}),F.on(\"table.remove.tool.panel\",function(){t(\".layui-table-tool-panel\").remove()}),R.on(\"resize\",function(){a.resize()})},d.init=function(e,i){i=i||{};var a=this,l=t(e?'table[lay-filter=\"'+e+'\"]':h+\"[lay-data]\"),n=\"Table element property lay-data configuration item has a syntax error: \";return l.each(function(){var a=t(this),l=a.attr(\"lay-data\");try{l=new Function(\"return \"+l)()}catch(r){o.error(n+l)}var c=[],s=t.extend({elem:this,cols:[],data:[],skin:a.attr(\"lay-skin\"),size:a.attr(\"lay-size\"),even:\"string\"==typeof a.attr(\"lay-even\")},d.config,i,l);e&&a.hide(),a.find(\"thead>tr\").each(function(e){s.cols[e]=[],t(this).children().each(function(i){var a=t(this),l=a.attr(\"lay-data\");try{l=new Function(\"return \"+l)()}catch(r){return o.error(n+l)}var d=t.extend({title:a.text(),colspan:a.attr(\"colspan\")||0,rowspan:a.attr(\"rowspan\")||0},l);d.colspan<2&&c.push(d),s.cols[e].push(d)})}),a.find(\"tbody>tr\").each(function(e){var i=t(this),a={};i.children(\"td\").each(function(e,i){var l=t(this),n=l.data(\"field\");if(n)return a[n]=l.html()}),layui.each(c,function(e,t){var l=i.children(\"td\").eq(e);a[t.field]=l.html()}),s.data[e]=a}),d.render(s)}),a},c.that={},c.config={},d.eachCols=function(e,i,a){var l=c.config[e]||{},n=[],o=0;a=t.extend(!0,[],a||l.cols),layui.each(a,function(e,t){layui.each(t,function(t,i){if(i.colGroup){var l=0;o++,i.CHILD_COLS=[],layui.each(a[e+1],function(e,t){t.PARENT_COL_INDEX||l>1&&l==i.colspan||(t.PARENT_COL_INDEX=o,i.CHILD_COLS.push(t),l+=parseInt(t.colspan>1?t.colspan:1))})}i.PARENT_COL_INDEX||n.push(i)})});var r=function(e){layui.each(e||n,function(e,t){return t.CHILD_COLS?r(t.CHILD_COLS):void(\"function\"==typeof i&&i(e,t))})};r()},d.checkStatus=function(e){var t=0,i=0,a=[],l=d.cache[e]||[];return layui.each(l,function(e,l){return l.constructor===Array?void i++:void(l[d.config.checkName]&&(t++,a.push(d.clearCacheKey(l))))}),{data:a,isAll:!!l.length&&t===l.length-i}},d.exportFile=function(e,t,i){t=t||d.clearCacheKey(d.cache[e]),i=i||\"csv\";var a=c.config[e]||{},l={csv:\"text/csv\",xls:\"application/vnd.ms-excel\"}[i],n=document.createElement(\"a\");return r.ie?o.error(\"IE_NOT_SUPPORT_EXPORTS\"):(n.href=\"data:\"+l+\";charset=utf-8,\\ufeff\"+encodeURIComponent(function(){var i=[],a=[];return layui.each(t,function(t,l){var n=[];\"object\"==typeof e?(layui.each(e,function(e,a){0==t&&i.push(a||\"\")}),layui.each(d.clearCacheKey(l),function(e,t){n.push('\"'+(t||\"\")+'\"')})):d.eachCols(e,function(e,a){a.field&&\"normal\"==a.type&&!a.hide&&(0==t&&i.push(a.title||\"\"),n.push('\"'+u(a,l[a.field],l,\"text\")+'\"'))}),a.push(n.join(\",\"))}),i.join(\",\")+\"\\r\\n\"+a.join(\"\\r\\n\")}()),n.download=(a.title||\"table_\"+(a.index||\"\"))+\".\"+i,document.body.appendChild(n),n.click(),void document.body.removeChild(n))},d.resize=function(e){if(e){var t=s(e);if(!t)return;c.that[e].resize()}else layui.each(c.that,function(){this.resize()})},d.reload=function(e,t){var i=s(e);if(i){var a=c.that[e];return a.reload(t),c.call(a)}},d.render=function(e){var t=new I(e);return c.call(t)},d.clearCacheKey=function(e){return e=t.extend({},e),delete e[d.config.checkName],delete e[d.config.indexName],e},d.init(),e(y,d)});layui.define(\"jquery\",function(e){\"use strict\";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t=\"carousel\",a=\"layui-this\",l=\">*[carousel-item]>*\",o=\"layui-carousel-left\",r=\"layui-carousel-right\",d=\"layui-carousel-prev\",s=\"layui-carousel-next\",u=\"layui-carousel-arrow\",c=\"layui-carousel-ind\",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:\"600px\",height:\"280px\",full:!1,arrow:\"hover\",indicator:\"inside\",autoplay:!0,interval:3e3,anim:\"\",trigger:\"click\",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:\"fixed\",width:\"100%\",height:\"100%\",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr(\"lay-anim\",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['<button class=\"layui-icon '+u+'\" lay-type=\"sub\">'+(\"updown\"===n.anim?\"&#xe619;\":\"&#xe603;\")+\"</button>\",'<button class=\"layui-icon '+u+'\" lay-type=\"add\">'+(\"updown\"===n.anim?\"&#xe61a;\":\"&#xe602;\")+\"</button>\"].join(\"\"));n.elem.attr(\"lay-arrow\",n.arrow),n.elem.find(\".\"+u)[0]&&n.elem.find(\".\"+u).remove(),n.elem.append(t),t.on(\"click\",function(){var n=i(this),t=n.attr(\"lay-type\");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['<div class=\"'+c+'\"><ul>',function(){var i=[];return layui.each(e.elemItem,function(e){i.push(\"<li\"+(n.index===e?' class=\"layui-this\"':\"\")+\"></li>\")}),i.join(\"\")}(),\"</ul></div>\"].join(\"\"));n.elem.attr(\"lay-indicator\",n.indicator),n.elem.find(\".\"+c)[0]&&n.elem.find(\".\"+c).remove(),n.elem.append(t),\"updown\"===n.anim&&t.css(\"margin-top\",-(t.height()/2)),t.find(\"li\").on(\"hover\"===n.trigger?\"mouseover\":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide(\"add\",a-n.index):a<n.index&&e.slide(\"sub\",n.index-a)})},m.prototype.slide=function(e,i){var n=this,l=n.elemItem,u=n.config,c=u.index,m=u.elem.attr(\"lay-filter\");n.haveSlide||(\"sub\"===e?(n.subIndex(i),l.eq(u.index).addClass(d),setTimeout(function(){l.eq(c).addClass(r),l.eq(u.index).addClass(r)},50)):(n.addIndex(i),l.eq(u.index).addClass(s),setTimeout(function(){l.eq(c).addClass(o),l.eq(u.index).addClass(o)},50)),setTimeout(function(){l.removeClass(a+\" \"+d+\" \"+s+\" \"+o+\" \"+r),l.eq(u.index).addClass(a),n.haveSlide=!1},300),n.elemInd.find(\"li\").eq(u.index).addClass(a).siblings().removeClass(a),n.haveSlide=!0,layui.event.call(this,t,\"change(\"+m+\")\",{index:u.index,prevIndex:c,item:l.eq(u.index)}))},m.prototype.events=function(){var e=this,i=e.config;i.elem.data(\"haveEvents\")||(i.elem.on(\"mouseenter\",function(){clearInterval(e.timer)}).on(\"mouseleave\",function(){e.autoplay()}),i.elem.data(\"haveEvents\",!0))},n.render=function(e){var i=new m(e);return i},e(t,n)});layui.define(\"jquery\",function(e){\"use strict\";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n=\"rate\",t=\"layui-rate\",o=\"layui-icon-rate\",s=\"layui-icon-rate-solid\",u=\"layui-icon-rate-half\",r=\"layui-icon-rate-solid layui-icon-rate-half\",c=\"layui-icon-rate-solid layui-icon-rate\",f=\"layui-icon-rate layui-icon-rate-half\",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:\"\"},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style=\"color: '+i.theme+';\"':\"\";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='<ul class=\"layui-rate\" '+(i.readonly?\"readonly\":\"\")+\">\",u=1;u<=i.length;u++){var r='<li class=\"layui-inline\"><i class=\"layui-icon '+(u>Math.floor(i.value)?o:s)+'\" '+l+\"></i></li>\";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'<li><i class=\"layui-icon layui-icon-rate-half\" '+l+\"></i></li>\":n+=r}n+=\"</ul>\"+(i.text?'<span class=\"layui-inline\">'+i.value+\"星\":\"\")+\"</span>\";var c=i.elem,f=c.next(\".\"+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next(\"span\"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass(\"layui-inline\"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find(\"i\").width();l.children(\"li\").each(function(e){var t=e+1,v=a(this);v.on(\"click\",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next(\"span\").text(i.value+\"星\"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on(\"mousemove\",function(e){if(l.find(\"i\").each(function(){a(this).addClass(o).removeClass(r)}),l.find(\"i:lt(\"+t+\")\").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children(\"i\").addClass(u).removeClass(s)}}),v.on(\"mouseleave\",function(){l.find(\"i\").each(function(){a(this).addClass(o).removeClass(r)}),l.find(\"i:lt(\"+Math.floor(i.value)+\")\").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children(\"li:eq(\"+Math.floor(i.value)+\")\").children(\"i\").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)});layui.define(\"jquery\",function(t){\"use strict\";var e=layui.$,i={fixbar:function(t){var i,n,a=\"layui-fixbar\",o=\"layui-fixbar-top\",r=e(document),l=e(\"body\");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?\"&#xe606;\":t.bar1,t.bar2=t.bar2===!0?\"&#xe607;\":t.bar2,t.bgcolor=t.bgcolor?\"background-color:\"+t.bgcolor:\"\";var c=[t.bar1,t.bar2,\"&#xe604;\"],g=e(['<ul class=\"'+a+'\">',t.bar1?'<li class=\"layui-icon\" lay-type=\"bar1\" style=\"'+t.bgcolor+'\">'+c[0]+\"</li>\":\"\",t.bar2?'<li class=\"layui-icon\" lay-type=\"bar2\" style=\"'+t.bgcolor+'\">'+c[1]+\"</li>\":\"\",'<li class=\"layui-icon '+o+'\" lay-type=\"top\" style=\"'+t.bgcolor+'\">'+c[2]+\"</li>\",\"</ul>\"].join(\"\")),s=g.find(\".\"+o),u=function(){var e=r.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e(\".\"+a)[0]||(\"object\"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find(\"li\").on(\"click\",function(){var i=e(this),n=i.attr(\"lay-type\");\"top\"===n&&e(\"html,body\").animate({scrollTop:0},200),t.click&&t.click.call(this,n)}),r.on(\"scroll\",function(){clearTimeout(n),n=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var n=this,a=\"function\"==typeof e,o=new Date(t).getTime(),r=new Date(!e||a?(new Date).getTime():e).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=e);var g=setTimeout(function(){n.countdown(t,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(t).getTime();return a>6912e5?(a=new Date(t),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),e||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join(\"-\")+\" \"+n[1].join(\":\")):a>=864e5?(a/1e3/60/60/24|0)+\"天前\":a>=36e5?(a/1e3/60/60|0)+\"小时前\":a>=12e4?(a/1e3/60|0)+\"分钟前\":a<0?\"未来\":\"刚刚\"},digit:function(t,e){var i=\"\";t=String(t),e=e||2;for(var n=t.length;n<e;n++)i+=\"0\";return t<Math.pow(10,e)?i+(0|t):t},toDateString:function(t,e){var i=this,n=new Date(t||new Date),a=[i.digit(n.getFullYear(),4),i.digit(n.getMonth()+1),i.digit(n.getDate())],o=[i.digit(n.getHours()),i.digit(n.getMinutes()),i.digit(n.getSeconds())];return e=e||\"yyyy-MM-dd HH:mm:ss\",e.replace(/yyyy/g,a[0]).replace(/MM/g,a[1]).replace(/dd/g,a[2]).replace(/HH/g,o[0]).replace(/mm/g,o[1]).replace(/ss/g,o[2])},escape:function(t){return String(t||\"\").replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")},event:function(t,n,a){n=i.event[t]=e.extend(!0,i.event[t],n)||{},e(\"body\").on(a||\"click\",\"*[\"+t+\"]\",function(){var i=e(this),a=i.attr(t);n[a]&&n[a].call(this,i)})}};!function(t,e,i){\"$:nomunge\";function n(){a=e[l](function(){o.each(function(){var e=t(this),i=e.width(),n=e.height(),a=t.data(this,g);(i!==a.w||n!==a.h)&&e.trigger(c,[a.w=i,a.h=n])}),n()},r[s])}var a,o=t([]),r=t.resize=t.extend(t.resize,{}),l=\"setTimeout\",c=\"resize\",g=c+\"-special-event\",s=\"delay\",u=\"throttleWindow\";r[s]=250,r[u]=!0,t.event.special[c]={setup:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===o.length&&n()},teardown:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.not(e),e.removeData(g),o.length||clearTimeout(a)},add:function(e){function n(e,n,o){var r=t(this),l=t.data(this,g)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[u]&&this[l])return!1;var a;return t.isFunction(e)?(a=e,n):(a=e.handler,void(e.handler=n))}}}(e,window),t(\"util\",i)});layui.define(\"jquery\",function(e){\"use strict\";var l=layui.$,o=function(e){},t='<i class=\"layui-anim layui-anim-rotate layui-anim-loop layui-icon \">&#xe63e;</i>';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!(\"isAuto\"in e)||e.isAuto,v=e.end||\"没有更多了\",y=e.scrollElem&&e.scrollElem!==document,d=\"<cite>加载更多</cite>\",h=l('<div class=\"layui-flow-more\"><a href=\"javascript:;\">'+d+\"</a></div>\");f.find(\".layui-flow-more\")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find(\"a\").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find(\"a\").html(t),\"function\"==typeof e.done&&e.done(++c,p)};if(g(),h.find(\"a\").on(\"click\",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+\" img\",scrollElem:e.scrollElem});return s?(m.on(\"scroll\",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop(\"scrollHeight\"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||\"img\",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr(\"src\")){var m=e.attr(\"lay-src\");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr(\"src\",m).removeAttr(\"lay-src\"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;s<t.lazyimg.elem.length;s++){var v=t.lazyimg.elem.eq(s),y=a?function(){return v.offset().top-n.offset().top+m}():v.offset().top;if(c(v,f),i=s,y>u)break}};if(f(),!o){var m;n.on(\"scroll\",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e(\"flow\",new o)});layui.define([\"layer\",\"form\"],function(t){\"use strict\";var e=layui.$,i=layui.layer,a=layui.form,l=(layui.hint(),layui.device()),n=\"layedit\",o=\"layui-show\",r=\"layui-disabled\",c=function(){var t=this;t.index=0,t.config={tool:[\"strong\",\"italic\",\"underline\",\"del\",\"|\",\"left\",\"center\",\"right\",\"|\",\"link\",\"unlink\",\"face\",\"image\"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r=\"layui-layedit\",c=e(\"string\"==typeof t?\"#\"+t:t),u=\"LAY_layedit_\"+ ++a.index,d=c.next(\".\"+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join(\"\")}(),m=e(['<div class=\"'+r+'\">','<div class=\"layui-unselect layui-layedit-tool\">'+f+\"</div>\",'<div class=\"layui-layedit-iframe\">','<iframe id=\"'+u+'\" name=\"'+u+'\" textarea=\"'+t+'\" frameborder=\"0\"></iframe>',\"</div>\",\"</div>\"].join(\"\"));return l.ie&&l.ie<8?c.removeClass(\"layui-hide\").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass(\"layui-hide\").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e(\"#\"+i[1].attr(\"textarea\"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find(\"iframe\");n.css({height:a.height}).on(\"load\",function(){var o=n.contents(),r=n.prop(\"contentWindow\"),c=o.find(\"head\"),s=e([\"<style>\",\"*{margin: 0; padding: 0;}\",\"body{padding: 10px; line-height: 20px; overflow-x: hidden; word-wrap: break-word; font: 14px Helvetica Neue,Helvetica,PingFang SC,Microsoft YaHei,Tahoma,Arial,sans-serif; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;}\",\"a{color:#01AAED; text-decoration:none;}a:hover{color:#c00}\",\"p{margin-bottom: 10px;}\",\"img{display: inline-block; border: none; vertical-align: middle;}\",\"pre{margin: 10px 0; padding: 10px; line-height: 20px; border: 1px solid #ddd; border-left-width: 6px; background-color: #F2F2F2; color: #333; font-family: Courier New; font-size: 12px;}\",\"</style>\"].join(\"\")),u=o.find(\"body\");c.append(s),u.attr(\"contenteditable\",\"true\").css({\"min-height\":a.height}).html(i.value||\"\"),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e(\"#LAY_layedit_\"+t),a=i.prop(\"contentWindow\");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on(\"keydown\",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if(\"pre\"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg(\"请暂时用shift+enter\"),!1}r.execCommand(\"formatBlock\",!1,\"<p>\")}}),e(n).parents(\"form\").on(\"submit\",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on(\"paste\",function(e){r.execCommand(\"formatBlock\",!1,\"<p>\"),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find(\"*[style]\").each(function(){var t=this.style.textAlign;this.removeAttribute(\"style\"),e(this).css({\"text-align\":t||\"\"})}),t.find(\"table\").addClass(\"layui-table\"),t.find(\"script,link\").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute(\"text\"),l.selection){var r=a.text||i.text;if(\"a\"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop(\"outerHTML\")),a.select()}else{var r=a.toString()||i.text;if(\"a\"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l=\"layedit-tool-active\",n=p(m(a)),o=function(e){return t.find(\".layedit-tool-\"+e)};i&&i[i.hasClass(l)?\"removeClass\":\"addClass\"](l),t.find(\">i\").removeClass(l),o(\"unlink\").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;\"b\"!==t&&\"strong\"!==t||o(\"b\").addClass(l),\"i\"!==t&&\"em\"!==t||o(\"i\").addClass(l),\"u\"===t&&o(\"u\").addClass(l),\"strike\"===t&&o(\"d\").addClass(l),\"p\"===t&&(\"center\"===e?o(\"center\").addClass(l):\"right\"===e?o(\"right\").addClass(l):o(\"left\").addClass(l)),\"a\"===t&&(o(\"link\").addClass(l),o(\"unlink\").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr(\"href\"),target:l.attr(\"target\")},function(e){var a=l[0];\"A\"===a.tagName?a.href=e.url:v.call(t,\"a\",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand(\"unlink\")},face:function(e){x.call(this,function(i){v.call(t,\"img\",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use(\"upload\",function(o){var r=l.uploadImage||{};o.render({url:r.url,method:r.type,elem:e(n).find(\"input\")[0],done:function(e){0==e.code?(e.data=e.data||{},v.call(t,\"img\",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||\"上传失败\")}})})},code:function(e){k.call(o,function(i){v.call(t,\"pre\",{text:i.code,\"lay-lang\":i.lang},e)})},help:function(){i.open({type:2,title:\"帮助\",area:[\"600px\",\"380px\"],shadeClose:!0,shade:.1,skin:\"layui-layer-msg\",content:[\"http://www.layui.com/about/layedit/help.html\",\"no\"]})}},s=a.find(\".layui-layedit-tool\"),u=function(){var i=e(this),a=i.attr(\"layedit-event\"),l=i.attr(\"lay-command\");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand(\"formatBlock\",!1,\"<p>\"),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(\">i\").on(\"mousedown\",function(){var t=e(this),i=t.attr(\"layedit-event\");d.test(i)||u.call(this)}).on(\"click\",function(){var t=e(this),i=t.attr(\"layedit-event\");d.test(i)&&u.call(this)}),o.on(\"click\",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:\"LAY_layedit_link\",area:\"350px\",shade:.05,shadeClose:!0,moveType:1,title:\"超链接\",skin:\"layui-layer-msg\",content:['<ul class=\"layui-form\" style=\"margin: 15px;\">','<li class=\"layui-form-item\">','<label class=\"layui-form-label\" style=\"width: 60px;\">URL</label>','<div class=\"layui-input-block\" style=\"margin-left: 90px\">','<input name=\"url\" lay-verify=\"url\" value=\"'+(t.href||\"\")+'\" autofocus=\"true\" autocomplete=\"off\" class=\"layui-input\">',\"</div>\",\"</li>\",'<li class=\"layui-form-item\">','<label class=\"layui-form-label\" style=\"width: 60px;\">打开方式</label>','<div class=\"layui-input-block\" style=\"margin-left: 90px\">','<input type=\"radio\" name=\"target\" value=\"_self\" class=\"layui-input\" title=\"当前窗口\"'+(\"_self\"!==t.target&&t.target?\"\":\"checked\")+\">\",'<input type=\"radio\" name=\"target\" value=\"_blank\" class=\"layui-input\" title=\"新窗口\" '+(\"_blank\"===t.target?\"checked\":\"\")+\">\",\"</div>\",\"</li>\",'<li class=\"layui-form-item\" style=\"text-align: center;\">','<button type=\"button\" lay-submit lay-filter=\"layedit-link-yes\" class=\"layui-btn\"> 确定 </button>','<button style=\"margin-left: 20px;\" type=\"button\" class=\"layui-btn layui-btn-primary\"> 取消 </button>',\"</li>\",\"</ul>\"].join(\"\"),success:function(t,n){var o=\"submit(layedit-link-yes)\";a.render(\"radio\"),t.find(\".layui-btn-primary\").on(\"click\",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=[\"[微笑]\",\"[嘻嘻]\",\"[哈哈]\",\"[可爱]\",\"[可怜]\",\"[挖鼻]\",\"[吃惊]\",\"[害羞]\",\"[挤眼]\",\"[闭嘴]\",\"[鄙视]\",\"[爱你]\",\"[泪]\",\"[偷笑]\",\"[亲亲]\",\"[生病]\",\"[太开心]\",\"[白眼]\",\"[右哼哼]\",\"[左哼哼]\",\"[嘘]\",\"[衰]\",\"[委屈]\",\"[吐]\",\"[哈欠]\",\"[抱抱]\",\"[怒]\",\"[疑问]\",\"[馋嘴]\",\"[拜拜]\",\"[思考]\",\"[汗]\",\"[困]\",\"[睡]\",\"[钱]\",\"[失望]\",\"[酷]\",\"[色]\",\"[哼]\",\"[鼓掌]\",\"[晕]\",\"[悲伤]\",\"[抓狂]\",\"[黑线]\",\"[阴险]\",\"[怒骂]\",\"[互粉]\",\"[心]\",\"[伤心]\",\"[猪头]\",\"[熊猫]\",\"[兔子]\",\"[ok]\",\"[耶]\",\"[good]\",\"[NO]\",\"[赞]\",\"[来]\",\"[弱]\",\"[草泥马]\",\"[神马]\",\"[囧]\",\"[浮云]\",\"[给力]\",\"[围观]\",\"[威武]\",\"[奥特曼]\",\"[礼物]\",\"[钟]\",\"[话筒]\",\"[蜡烛]\",\"[蛋糕]\"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+\"images/face/\"+t+\".gif\"}),e}();return x.hide=x.hide||function(t){\"face\"!==e(t.target).attr(\"layedit-event\")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('<li title=\"'+e+'\"><img src=\"'+i+'\" alt=\"'+e+'\"></li>')}),'<ul class=\"layui-clear\">'+t.join(\"\")+\"</ul>\"}(),this,{tips:1,time:0,skin:\"layui-box layui-util-face\",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(\".layui-clear>li\").on(\"click\",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off(\"click\",x.hide).on(\"click\",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:\"LAY_layedit_code\",area:\"550px\",shade:.05,shadeClose:!0,moveType:1,title:\"插入代码\",skin:\"layui-layer-msg\",content:['<ul class=\"layui-form layui-form-pane\" style=\"margin: 15px;\">','<li class=\"layui-form-item\">','<label class=\"layui-form-label\">请选择语言</label>','<div class=\"layui-input-block\">','<select name=\"lang\">','<option value=\"JavaScript\">JavaScript</option>','<option value=\"HTML\">HTML</option>','<option value=\"CSS\">CSS</option>','<option value=\"Java\">Java</option>','<option value=\"PHP\">PHP</option>','<option value=\"C#\">C#</option>','<option value=\"Python\">Python</option>','<option value=\"Ruby\">Ruby</option>','<option value=\"Go\">Go</option>',\"</select>\",\"</div>\",\"</li>\",'<li class=\"layui-form-item layui-form-text\">','<label class=\"layui-form-label\">代码</label>','<div class=\"layui-input-block\">','<textarea name=\"code\" lay-verify=\"required\" autofocus=\"true\" class=\"layui-textarea\" style=\"height: 200px;\"></textarea>',\"</div>\",\"</li>\",'<li class=\"layui-form-item\" style=\"text-align: center;\">','<button type=\"button\" lay-submit lay-filter=\"layedit-code-yes\" class=\"layui-btn\"> 确定 </button>','<button style=\"margin-left: 20px;\" type=\"button\" class=\"layui-btn layui-btn-primary\"> 取消 </button>',\"</li>\",\"</ul>\"].join(\"\"),success:function(l,n){var o=\"submit(layedit-code-yes)\";a.render(\"select\"),l.find(\".layui-btn-primary\").on(\"click\",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'<i class=\"layui-icon layedit-tool-html\" title=\"HTML源代码\" lay-command=\"html\" layedit-event=\"html\"\">&#xe64b;</i><span class=\"layedit-tool-mid\"></span>',strong:'<i class=\"layui-icon layedit-tool-b\" title=\"加粗\" lay-command=\"Bold\" layedit-event=\"b\"\">&#xe62b;</i>',italic:'<i class=\"layui-icon layedit-tool-i\" title=\"斜体\" lay-command=\"italic\" layedit-event=\"i\"\">&#xe644;</i>',underline:'<i class=\"layui-icon layedit-tool-u\" title=\"下划线\" lay-command=\"underline\" layedit-event=\"u\"\">&#xe646;</i>',del:'<i class=\"layui-icon layedit-tool-d\" title=\"删除线\" lay-command=\"strikeThrough\" layedit-event=\"d\"\">&#xe64f;</i>',\"|\":'<span class=\"layedit-tool-mid\"></span>',left:'<i class=\"layui-icon layedit-tool-left\" title=\"左对齐\" lay-command=\"justifyLeft\" layedit-event=\"left\"\">&#xe649;</i>',center:'<i class=\"layui-icon layedit-tool-center\" title=\"居中对齐\" lay-command=\"justifyCenter\" layedit-event=\"center\"\">&#xe647;</i>',right:'<i class=\"layui-icon layedit-tool-right\" title=\"右对齐\" lay-command=\"justifyRight\" layedit-event=\"right\"\">&#xe648;</i>',link:'<i class=\"layui-icon layedit-tool-link\" title=\"插入链接\" layedit-event=\"link\"\">&#xe64c;</i>',unlink:'<i class=\"layui-icon layedit-tool-unlink layui-disabled\" title=\"清除链接\" lay-command=\"unlink\" layedit-event=\"unlink\"\">&#xe64d;</i>',face:'<i class=\"layui-icon layedit-tool-face\" title=\"表情\" layedit-event=\"face\"\">&#xe650;</i>',image:'<i class=\"layui-icon layedit-tool-image\" title=\"图片\" layedit-event=\"image\">&#xe64a;<input type=\"file\" name=\"file\"></i>',code:'<i class=\"layui-icon layedit-tool-code\" title=\"插入代码\" layedit-event=\"code\">&#xe64e;</i>',help:'<i class=\"layui-icon layedit-tool-help\" title=\"帮助\" layedit-event=\"help\">&#xe607;</i>'},w=new c;t(n,w)});layui.define(\"jquery\",function(e){\"use strict\";var a=layui.$,l=\"http://www.layui.com/doc/modules/code.html\";e(\"code\",function(e){var t=[];e=e||{},e.elem=a(e.elem||\".layui-code\"),e.about=!(\"about\"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr(\"lay-encode\")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\")),c.html('<ol class=\"layui-code-ol\"><li>'+o.replace(/[\\r\\t\\n]+/g,\"</li><li>\")+\"</li></ol>\"),c.find(\">.layui-code-h3\")[0]||c.prepend('<h3 class=\"layui-code-h3\">'+(c.attr(\"lay-title\")||e.title||\"code\")+(e.about?'<a href=\"'+l+'\" target=\"_blank\">layui.code</a>':\"\")+\"</h3>\");var d=c.find(\">.layui-code-ol\");c.addClass(\"layui-box layui-code-view\"),(c.attr(\"lay-skin\")||e.skin)&&c.addClass(\"layui-code-\"+(c.attr(\"lay-skin\")||e.skin)),(d.find(\"li\").length/100|0)>0&&d.css(\"margin-left\",(d.find(\"li\").length/100|0)+\"px\"),(c.attr(\"lay-height\")||e.height)&&d.css(\"max-height\",c.attr(\"lay-height\")||e.height)})})}).addcss(\"modules/code.css\",\"skincodecss\");"
  },
  {
    "path": "src/main/webapp/static/layui/layui.js",
    "content": "/** layui-v2.5.4 MIT License By https://www.layui.com */\n ;!function(e){\"use strict\";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v=\"2.5.4\"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if(\"interactive\"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),i=function(t){e.console&&console.error&&console.error(\"Layui hint: \"+t)},a=\"undefined\"!=typeof opera&&\"[object Opera]\"===opera.toString(),u={layer:\"modules/layer\",laydate:\"modules/laydate\",laypage:\"modules/laypage\",laytpl:\"modules/laytpl\",layim:\"modules/layim\",layedit:\"modules/layedit\",form:\"modules/form\",upload:\"modules/upload\",transfer:\"modules/transfer\",tree:\"modules/tree\",table:\"modules/table\",element:\"modules/element\",rate:\"modules/rate\",colorpicker:\"modules/colorpicker\",slider:\"modules/slider\",carousel:\"modules/carousel\",flow:\"modules/flow\",util:\"modules/util\",code:\"modules/code\",jquery:\"modules/jquery\",mobile:\"modules/mobile\",\"layui.all\":\"../layui.all\"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r=\"function\"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return\"function\"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),!layui[\"layui.all\"]&&layui[\"layui.mobile\"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n=\"PLaySTATION 3\"===navigator.platform?/^complete$/:/^(complete|loaded)$/;(\"load\"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+\" is not a valid module\"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):\"function\"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName(\"head\")[0];e=\"string\"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){\"jquery\"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\\/\\/([\\s\\S]+?)\\//)||[\"//\"+location.host+\"/\"])[0],0===e.length||layui[\"layui.all\"]&&u[f]||!layui[\"layui.all\"]&&layui[\"layui.mobile\"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+\" is not a valid module\"):void(\"string\"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement(\"script\"),h=(u[f]?p+\"lay/\":/^\\{\\/\\}/.test(y.modules[f])?\"\":o.base||\"\")+(y.modules[f]||f)+\".js\";h=h.replace(/^\\{\\/\\}/,\"\"),v.async=!0,v.charset=\"utf-8\",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||\"\";return e?\"?v=\"+e:\"\"}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf(\"[native code\")<0||a?v.addEventListener(\"load\",function(e){s(e,h)},!1):v.attachEvent(\"onreadystatechange\",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement(\"link\"),l=t.getElementsByTagName(\"head\")[0];\"string\"==typeof n&&(r=n);var s=(r||e).replace(/\\.|\\//g,\"\"),c=u.id=\"layuicss-\"+s,y=0;return u.rel=\"stylesheet\",u.href=e+(o.debug?\"?v=\"+(new Date).getTime():\"\"),u.media=\"all\",t.getElementById(c)||l.appendChild(u),\"function\"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+\" timeout\"):void(1989===parseInt(a.getStyle(t.getElementById(c),\"width\"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return\"function\"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+\"css/\"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,\"function\"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,\"function\"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i(\"模块名 \"+o+\" 已被占用\"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||\"\"};return/^#\\//.test(e)?(e=e.replace(/^#\\//,\"\"),o.href=\"/\"+e,e=e.replace(/([^#])(#.*$)/,\"$1\").split(\"/\")||[],t.each(e,function(e,t){/^\\w+=/.test(t)?function(){t=t.split(\"=\"),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||\"layui\",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o=\"object\"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return\"value\"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+\"/([^\\\\s\\\\_\\\\-]+)\");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?\"windows\":/linux/.test(o)?\"linux\":/iphone|ipod|ipad|ios/.test(o)?\"ios\":/mac/.test(o)?\"mac\":void 0}(),ie:function(){return!!(e.ActiveXObject||\"ActiveXObject\"in e)&&((o.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),weixin:n(\"micromessenger\")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios=\"ios\"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if(\"function\"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;o<e.length&&!t.call(e[o],o,e[o]);o++);return n},n.prototype.sort=function(e,t,o){var n=JSON.parse(JSON.stringify(e||[]));return t?(n.sort(function(e,o){var n=/^-?\\d+$/,r=e[t],i=o[t];return n.test(r)&&(r=parseFloat(r)),n.test(i)&&(i=parseFloat(i)),r&&!i?1:!r&&i?-1:r>i?1:r<i?-1:0}),o&&n.reverse(),n):n},n.prototype.stope=function(t){t=t||e.event;try{t.stopPropagation()}catch(o){t.cancelBubble=!0}},n.prototype.onevent=function(e,t,o){return\"string\"!=typeof e||\"function\"!=typeof o?this:n.event(e,t,null,o)},n.prototype.event=n.event=function(e,t,n,r){var i=this,a=null,u=t.match(/\\((.*)\\)$/)||[],l=(e+\".\"+t).replace(u[0],\"\"),s=u[1]||\"\",c=function(e,t){var o=t&&t.call(i,n);o===!1&&null===a&&(a=!1)};return r?(o.event[l]=o.event[l]||{},o.event[l][s]=[r],this):(layui.each(o.event[l],function(e,t){return\"{*}\"===s?void layui.each(t,c):(\"\"===e&&layui.each(t,c),void(s&&e===s&&layui.each(t,c)))}),a)},e.layui=new n}(window);"
  },
  {
    "path": "target/classes/com/mapper/CinemaMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.CinemaMapper\">\n\t<resultMap type=\"com.entity.Cinema\" id=\"BaseResultMap\">\n\t\t<id property=\"cinema_id\" column=\"cinema_id\" javaType=\"long\"/>\n\t\t<result property=\"cinema_name\" column=\"cinema_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"cinema_address\" column=\"cinema_address\" javaType=\"java.lang.String\"/>\n\t</resultMap>\n\t\n\t<select id=\"findCinemaById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from cinema where cinema_id = #{cinema_id}\n\t</select>\n\t\n\t<select id=\"findAllCinemas\" resultMap=\"BaseResultMap\">\n\t\tselect * from cinema\n\t</select>\n\t\n\t<select id=\"findCinemasLikeName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from cinema where cinema_name like '%${value}%'\n\t</select>\n\t\n\t<select id=\"findCinemasByMovieId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect distinct cinema.* from hall,schedule,cinema\n\t\twhere hall.hall_id=schedule.hall_id and hall.cinema_id=cinema.cinema_id and schedule.movie_id = #{movie_id}\n\t</select>\n\t\n\t<insert id=\"addCinema\" parameterType=\"com.entity.Cinema\">\n\t\tinsert into cinema(cinema_name,cinema_address)\n\t\tvalues(#{cinema_name},#{cinema_address})\n\t</insert>\n\t\n\t<update id=\"updateCinema\" parameterType=\"com.entity.Cinema\">\n\t\tupdate cinema\n\t\t<set>\n\t\t\tcinema_name = #{cinema_name},\n\t\t\tcinema_address = #{cinema_address}\n\t\t</set>\n\t\twhere cinema_id = #{cinema_id}\n\t</update>\n\t\n\t<delete id=\"deleteCinema\" parameterType=\"long\">\n\t\tdelete from cinema where cinema_id = #{cinema_id}\n\t</delete>\n</mapper>"
  },
  {
    "path": "target/classes/com/mapper/CommentMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.CommentMapper\">\n\t<resultMap type=\"com.entity.Comment\" id=\"BaseResultMap\">\n\t\t<id property=\"comment_id\" column=\"comment_id\" javaType=\"long\"/>\n\t\t<result property=\"comment_content\" column=\"comment_content\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"comment_time\" column=\"comment_time\" javaType=\"java.util.Date\"/>\n\t\t<result property=\"movie_id\" column=\"movie_id\" javaType=\"long\"/>\n\t\t<result property=\"user_id\" column=\"user_id\" javaType=\"long\"/>\n\t</resultMap>\n\t\n\t<select id=\"findCommentById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from comment where comment_id = #{comment_id}\n\t</select>\n\t\n\t<select id=\"findAllComments\" resultMap=\"BaseResultMap\">\n\t\tselect * from comment\n\t</select>\n\t\n\t<select id=\"findCommentsByUserName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect comment.* from comment,user where comment.user_id = user.user_id and user.user_name = #{user_name}\n\t</select>\n\t\n\t<select id=\"findCommentsByMoiveId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from comment where movie_id = #{movie_id}\n\t</select>\n\t\n\t<insert id=\"addComemnt\" parameterType=\"com.entity.Comment\">\n\t\tinsert into comment(comment_content,comment_time,movie_id,user_id)\n\t\tvalues(#{comment_content},#{comment_time},#{movie_id},#{user_id})\n\t</insert>\n\t\n\t<update id=\"updateComment\" parameterType=\"com.entity.Comment\">\n\t\tupdate comment\n\t\t<set>\n\t\t\tcomment_content = #{comment_content},\n\t\t\tcomment_time = #{comment_time},\n\t\t\tmovie_id = #{movie_id},\n\t\t\tuser_id = #{user_id}\n\t\t</set>\n\t\twhere comment_id = #{comment_id}\n\t</update>\n\t\n\t<delete id=\"deleteComment\" parameterType=\"long\">\n\t\tdelete from comment where comment_id = #{comment_id}\n\t</delete>\n\t\n</mapper>"
  },
  {
    "path": "target/classes/com/mapper/HallMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.HallMapper\">\n\t<resultMap type=\"com.entity.Hall\" id=\"BaseResultMap\">\n\t\t<id property=\"hall_id\" column=\"hall_id\" javaType=\"long\"/>\n\t\t<result property=\"hall_name\" column=\"hall_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"cinema_id\" column=\"cinema_id\" javaType=\"long\"/>\n\t</resultMap>\n\t\n\t<select id=\"findHallById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from hall where hall_id = #{hall_id}\n\t</select>\n\t\n\t<select id=\"findHallByCinemaAndHallName\" resultMap=\"BaseResultMap\">\n\t\tselect hall.* from hall,cinema where hall.cinema_id = cinema.cinema_id \n\t\tand cinema_name = #{cinema_name} and hall_name= #{hall_name}\n\t</select>\n\t\t\n\t<select id=\"findHallByCinemaId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from hall where cinema_id = #{cinema_id}\n\t</select>\n\t\n\t<select id=\"findAllHalls\" resultMap=\"BaseResultMap\">\n\t\tselect * from hall\n\t</select>\n\t\n\t<insert id=\"addHall\" parameterType=\"com.entity.Hall\">\n\t\tinsert into hall(hall_name,movie_id)\n\t\tvalues(hall_name,movie_id)\n\t</insert>\n\t\n\t<update id=\"updateHall\" parameterType=\"com.entity.Hall\">\n\t\tupdate hall\n\t\t<set>\n\t\t\thall_name = #{hall_name},\n\t\t\tmovie_id = #{movie_id}\n\t\t</set>\n\t\twhere hall_id = #{hall_id}\n\t</update>\n\t\n\t<delete id=\"deleteHall\" parameterType=\"long\">\n\t\tdelete from hall where hall_id = #{hall_id}\n\t</delete>\n</mapper>"
  },
  {
    "path": "target/classes/com/mapper/MovieMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.MovieMapper\">\n\t<resultMap type=\"com.entity.Movie\" id=\"BaseResultMap\">\n\t\t<id property=\"movie_id\" column=\"movie_id\" javaType=\"long\"/>\n\t\t<result property=\"movie_actor\" column=\"movie_actor\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_boxOffice\" column=\"movie_boxOffice\" javaType=\"float\"/>  \n\t\t<result property=\"movie_cn_name\" column=\"movie_cn_name\" javaType=\"java.lang.String\"/>  \n\t\t<result property=\"movie_commentCount\" column=\"movie_commentCount\" javaType=\"long\"/>  \n\t\t<result property=\"movie_country\" column=\"movie_country\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_detail\" column=\"movie_detail\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_director\" column=\"movie_director\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_duration\" column=\"movie_duration\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_fg_name\" column=\"movie_fg_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_picture\" column=\"movie_picture\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_score\" column=\"movie_score\" javaType=\"float\"/>\n\t\t<result property=\"movie_type\" column=\"movie_type\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"movie_releaseDate\" column=\"movie_releaseDate\" javaType=\"java.sql.Date\"/>\n\t\t<result property=\"movie_state\" column=\"movie_state\" javaType=\"java.lang.Integer\"/>\n\t</resultMap>\n\t\n\t<select id=\"findMovieById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_id = #{movie_id}\n\t</select>\n\t\n\t<select id=\"findMovieByName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_cn_name = #{movie_cn_name}\n\t</select>\n\t\n\t<insert id=\"addMovie\" parameterType=\"com.entity.Movie\">\n\t\tinsert into movie(movie_cn_name,movie_fg_name,movie_actor,movie_director,movie_detail,movie_duration,movie_type,movie_score,movie_releaseDate,movie_country,movie_picture)\n\t\tvalues(#{movie_cn_name},#{movie_fg_name},#{movie_actor},#{movie_director},#{movie_detail},#{movie_duration},#{movie_type},#{movie_score},#{movie_releaseDate},#{movie_country},#{movie_picture})\n\t</insert>\n\t\n\t<update id=\"deleteMovie\" parameterType=\"long\">\n\t\tupdate movie\n\t\t<set>\n\t\t\tmovie_state = 0\n\t\t</set>\n\t\twhere movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"changeMovieBoxOffice\">\n\t\tupdate movie set movie_boxOffice = movie_boxOffice + #{movie_boxOffice} where movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"updateMovie\" parameterType=\"com.entity.Movie\">\n\t\tupdate movie\n\t\t<set>\n\t\t\tmovie_cn_name = #{movie_cn_name},\n\t\t\tmovie_fg_name = #{movie_fg_name},\n\t\t\tmovie_actor = #{movie_actor},\n\t\t\tmovie_director = #{movie_director},\n\t\t\tmovie_detail = #{movie_detail},\n\t\t\tmovie_duration = #{movie_duration},\n\t\t\tmovie_type = #{movie_type},\n\t\t\tmovie_country = #{movie_country},\n\t\t\tmovie_picture = #{movie_picture}\n\t\t</set>\n\t\twhere movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"deleteMovieCommentCount\" parameterType=\"long\">\n\t\tupdate movie set movie_commentCount = movie_commentCount -1 where movie_id = #{movie_id}\n\t</update>\n\t\n\t<update id=\"addMovieCommentCount\" parameterType=\"long\">\n\t\tupdate movie set movie_commentCount = movie_commentCount +1 where movie_id = #{movie_id}\n\t</update>\n\t\n\t<select id=\"findAllMovies\" parameterType=\"java.lang.Integer\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = #{movie_state}\n\t</select>\n\t\n\t<select id=\"findMoviesLikeName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_cn_name like '%${value}%' and movie_state = 1\n\t</select>\n\t\n\t<select id=\"findMoviesLikeType\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_type like '%${value}%' and movie_state = 1\n\t</select>\n\t\n\t<select id=\"sortMovieByDate\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1  order by movie_releaseDate DESC\n\t</select>\n\t\n\t<select id=\"sortMovieByCount\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1 order by movie_commentCount DESC\n\t</select>\n\t\n\t<select id=\"sortMovieByScore\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1 order by movie_score DESC\n\t</select>\n\t\n\t<select id=\"sortMovieByBoxOffice\" resultMap=\"BaseResultMap\">\n\t\tselect * from movie where movie_state = 1 order by movie_boxOffice desc\n\t</select>\n\t\n</mapper>"
  },
  {
    "path": "target/classes/com/mapper/OrderMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.OrderMapper\">\n\t<resultMap type=\"com.entity.Order\" id=\"BaseResultMap\">\n\t\t<id property=\"order_id\" column=\"order_id\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"order_position\" column=\"order_position\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"order_state\" column=\"order_state\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"schedule_id\" column=\"schedule_id\" javaType=\"long\"/>\n\t\t<result property=\"user_id\" column=\"user_id\" javaType=\"long\"/>\n\t\t<result property=\"order_price\" column=\"order_price\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"order_time\" column=\"order_time\" javaType=\"java.util.Date\"/>\n\t</resultMap>\n\t\n\t<select id=\"findOrderById\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo where order_id = #{order_id}\n\t</select>\n\t\n\t<select id=\"findAllOrders\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo order by order_time desc\n\t</select>\n\t\n\t\n\t<select id=\"findOrdersByScheduleId\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo where schedule_id = #{schedule_id} and order_state != 2 order by order_time desc\n\t</select>\n\t\n\t<select id=\"findOrdersByState\" parameterType=\"int\" resultMap=\"BaseResultMap\">\n\t\tselect * from orderinfo where order_state = #{order_state} order by order_time desc\n\t</select>\n\t\n\t<select id=\"findOrdersByUserName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect orderinfo.*  from orderinfo,user where orderinfo.user_id = user.user_id and user.user_name = #{user_name} order by order_time desc\n\t</select>\n\t\n\t<select id=\"findRefundOrderByUserName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect orderinfo.*  from orderinfo,user where orderinfo.user_id = user.user_id and user.user_name = #{user_name} and orderinfo.order_state = 0 order by order_time desc\n\t</select>\n\t<insert id=\"addOrder\" parameterType=\"com.entity.Order\">\n\t\tinsert into orderinfo(order_id,order_position,schedule_id,user_id,order_price,order_time)\n\t\tvalues(#{order_id},#{order_position},#{schedule_id},#{user_id},#{order_price},#{order_time})\n\t</insert>\n\t\n\t<update id=\"updateOrderStateToRefund\" parameterType=\"java.lang.String\">\n\t\tupdate orderinfo set order_state = 0 where order_id = #{order_id}\n\t</update>\n\t\n\t<update id=\"updateOrderStateToRefunded\" parameterType=\"java.lang.String\">\n\t\tupdate orderinfo set order_state = 2 where order_id = #{order_id}\n\t</update>\n</mapper>"
  },
  {
    "path": "target/classes/com/mapper/ScheduleMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.ScheduleMapper\">\n\t<resultMap type=\"com.entity.Schedule\" id=\"BaseResultMap\">\n\t\t<id property=\"schedule_id\" column=\"schedule_id\" javaType=\"long\"/>\n\t\t<result property=\"hall_id\" column=\"hall_id\" javaType=\"long\"/>\n\t\t<result property=\"movie_id\" column=\"movie_id\" javaType=\"long\"/>\n\t\t<result property=\"schedule_price\" column=\"schedule_price\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"schedule_remain\" column=\"schedule_remain\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"schedule_startTime\" column=\"schedule_startTime\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"schedule_state\" column=\"schedule_state\" javaType=\"java.lang.Integer\"/>\n\t</resultMap>\n\t\n\t<select id=\"findScheduleById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from schedule where schedule_id = #{schedule_id}\n\t</select>\n\t\n\t<select id=\"findScheduleByState\" parameterType=\"java.lang.Integer\" resultMap=\"BaseResultMap\">\n\t\tselect * from schedule where schedule_state = #{schedule_state}\n\t</select>\n\t\n\t<select id=\"findScheduleByCinemaAndMovie\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,hall where schedule.hall_id=hall.hall_id\n\t\t and hall.cinema_id = #{cinema_id} and movie_id = #{movie_id} and schedule_state = 1\n\t</select>\n\t\n\t<select id=\"findScheduleByCinemaAndMovieAndHall\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,hall where schedule.hall_id=hall.hall_id\n\t\t and hall.cinema_id = #{cinema_id} and movie_id = #{movie_id} and schedule.hall_id = #{hall_id} and schedule_state = 1\n\t</select>\n\t\n\t<select id=\"findAllSchedule\" resultMap=\"BaseResultMap\">\n\t\tselect * from schedule\n\t</select>\n\t\n\t<select id=\"findScheduleByMovieName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,movie\n\t\twhere schedule.movie_id = movie.movie_id and schedule.schedule_state = 1 and movie.movie_cn_name like '%${value}%'\n\t</select>\n\t\n\t<select id=\"findOffScheduleByMovieName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect schedule.* from schedule,movie\n\t\twhere schedule.movie_id = movie.movie_id and schedule.schedule_state = 0 and movie.movie_cn_name like '%${value}%'\n\t</select>\n\t\n\t<insert id=\"addSchedule\" parameterType=\"com.entity.Schedule\">\n\t\tinsert into schedule(hall_id,movie_id,schedule_price,schedule_remain,schedule_startTime)\n\t\tvalues(#{hall_id},#{movie_id},#{schedule_price},#{schedule_remain},#{schedule_startTime})\n\t</insert>\n\t\n\t<update id=\"updateSchedule\" parameterType=\"com.entity.Schedule\">\n\t\tupdate schedule\n\t\t<set>\n\t\t\tschedule_price = #{schedule_price}\n\t\t</set>\n\t\twhere schedule_id = #{schedule_id}\n\t</update>\n\t\n\t<update id=\"deleteSchedule\" parameterType=\"long\">\n\t\tupdate schedule set schedule_state = 0 where schedule_id = #{schedule_id}\n\t</update>\n\t\n\t<update id=\"addScheduleRemain\" parameterType=\"long\">\n\t\tupdate schedule set schedule_remain = schedule_remain + 1 where schedule_id = #{schedule_id}\n\t</update>\n\t\n\t<update id=\"delScheduleRemain\" parameterType=\"long\">\n\t\tupdate schedule set schedule_remain = schedule_remain - 1 where schedule_id = #{schedule_id}\n\t</update>\n</mapper>"
  },
  {
    "path": "target/classes/com/mapper/UserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\nPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.mapper.UserMapper\">\n\t<resultMap type=\"com.entity.User\" id=\"BaseResultMap\">\n\t\t<id property=\"user_id\" column=\"user_id\" javaType=\"long\"/>\n\t\t<result property=\"user_name\" column=\"user_name\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"user_pwd\" column=\"user_pwd\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"user_email\" column=\"user_email\" javaType=\"java.lang.String\"/>\n\t\t<result property=\"user_role\" column=\"user_role\" javaType=\"java.lang.Integer\"/>\n\t\t<result property=\"user_headImg\" column=\"user_headImg\" javaType=\"java.lang.String\"/>\n\t</resultMap>\n\t<select id=\"findUserById\" parameterType=\"long\" resultMap=\"BaseResultMap\">\n\t\tselect * from user where user_id = #{id}\n\t</select>\n\t<select id=\"findAllUser\" resultMap=\"BaseResultMap\">\n\t\tselect * from user\n\t</select>\n\t<select id=\"findUserByName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from user where user_name = #{name}\n\t</select>\n\t<select id=\"findUserLikeName\" parameterType=\"java.lang.String\" resultMap=\"BaseResultMap\">\n\t\tselect * from user where user_name like '%${value}%'\n\t</select>\n\t<insert id=\"addUser\" parameterType=\"com.entity.User\">\n\t\tinsert into user(user_name,user_pwd,user_email)\n\t\tvalues(#{user_name},#{user_pwd},#{user_email})\n\t</insert>\n\t<update id=\"updateUser\" parameterType=\"com.entity.User\">\n\t\tupdate user \n\t\t<set>\n\t\t\t<if test=\"user_name!=null\">\n\t\t\t\tuser_name = #{user_name},\n\t\t\t</if>\n\t\t\t<if test=\"user_pwd!=null\">\n\t\t\t\tuser_pwd = #{user_pwd},\n\t\t\t</if>\n\t\t\t\tuser_email = #{user_email},\n\t\t\t\tuser_headImg = #{user_headImg}\n\t\t</set>\n\t\twhere user_id = #{user_id}\n\t</update>\n</mapper>"
  },
  {
    "path": "target/classes/mybatis.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<!-- 定义别名 -->\n\t<typeAliases>\n\t\t<package name=\"com.mapper\"/>\n\t</typeAliases>\n\t\n\t<!-- 配置 mybatis的分页插件 -->\n\t<plugins>\n\t\t<!-- com.github.pagehelper 为 PageHelper类所在包名 -->\n\t\t<plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n\t\t\t<!-- 分页参数合理化，默认为false。\n\t\t\t  启动合理化时，如果pageNum < 1 会查询第一页，\n\t\t\t  如果pageNum > pages 会查询最后一页；\n\t\t\t禁用合理化时，如果pageNum < 1或pageNum > pages会返回空数据。 -->\n\t\t\t<property name=\"reasonable\" value=\"true\"/>\n\t\t\t<!-- 设置数据库类型Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreS -->\n\t\t\t<property name=\"helpetrDialect\" value=\"mysql\"/>\n\t\t</plugin>\n\t</plugins>\n\t<!-- mapper映射 -->\n\t<mappers>\n\t\t<package name=\"com.mapper\"/>\n\t</mappers>\n\t\n</configuration>"
  },
  {
    "path": "target/classes/mysql.properties",
    "content": "driver=com.mysql.cj.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/movie?serverTimezone=UTC\nusername=root\npassword=root"
  },
  {
    "path": "target/classes/spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\" xmlns:mvc=\"http://www.springframework.org/schema/mvc\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:p=\"http://www.springframework.org/schema/p\" xmlns:mongo=\"http://www.springframework.org/schema/data/mongo\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/data/mongo \n\t\thttp://www.springframework.org/schema/data/mongo/spring-mongo-1.8.xsd\n\t\thttp://www.springframework.org/schema/aop \n\t\thttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd\n\t\thttp://www.springframework.org/schema/mvc\n\t\thttp://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd\n\t\thttp://www.springframework.org/schema/beans \n\t\thttp://www.springframework.org/schema/beans/spring-beans-4.0.xsd\n\t\thttp://www.springframework.org/schema/tx \n\t\thttp://www.springframework.org/schema/tx/spring-tx-4.0.xsd\n\t\thttp://www.springframework.org/schema/context \n\t\thttp://www.springframework.org/schema/context/spring-context-4.0.xsd\">\n\t\t\n\t<!-- 引入属性文件，获取配置参数 -->\n    <bean id=\"propertyConfigurer\" class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">  \n\t\t<property name=\"location\" value=\"classpath:mysql.properties\" /> \n\t</bean>\n\t\n\t <!-- 使用阿里巴巴的数据库连接池 -->\n\t<bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\"  destroy-method=\"close\">  \n\t\t<property name=\"driverClassName\" value=\"${driver}\" />  \n\t\t<property name=\"url\" value=\"${url}\" />  \n\t\t<property name=\"username\" value=\"${username}\" />  \n\t\t<property name=\"password\" value=\"${password}\" /> \n\t\t<!-- 连接池参数 --> \n\t\t<property name=\"maxActive\" value=\"800\"/>\n       \t<property name=\"minIdle\" value=\"10\"/>\n\t</bean>  \n\t\n\t<!-- 注册sqlSessionFactoryBean -->\n\t<!-- spring和MyBatis完美整合，不需要单独配置mybatis的映射文件 -->\t\n\t<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<!-- 指定数据源  连接池 -->\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t\t<!-- 指定 mybatis 主配置文件 -->\n\t\t<property name=\"configLocation\" value=\"classpath:mybatis.xml\"/>\n\t</bean>\n\t\n\t<!-- Mapper接口所在的包名，Spring会自动找到其下的类 -->\n\t<!-- 生产dao代理对象 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<property name=\"basePackage\" value=\"com.mapper\" />\n\t\t<property name=\"sqlSessionFactoryBeanName\" value=\"sqlSessionFactory\"></property>\n\t</bean>\n\t\n\t<!-- 注册事务管理器 -->\n\t<bean id=\"transactionManager\"  class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\t\n\t<!--支持注解驱动的事务管理，指定事务管理器 -->\n   \t<tx:annotation-driven transaction-manager=\"transactionManager\"/>\n   \t\n   \t<!--自动扫描IOC组件  -->\n    <context:component-scan base-package=\"com\"></context:component-scan>\n \t\n \t<!-- 开启aspectj代理 -->\n \t<aop:aspectj-autoproxy/>\n \t\n \t\n\t<!-- Jackson配置-->\n\t<bean id=\"objectMapper\" class=\"com.fasterxml.jackson.databind.ObjectMapper\">\n\t\t<property name=\"serializationInclusion\" value=\"NON_NULL\" />\n\t\t<property name=\"dateFormat\">\n\t\t\t<bean class=\"java.text.SimpleDateFormat\">\n\t\t\t\t<constructor-arg value=\"yyyy-MM-dd HH:mm:ss\" />\n\t\t\t</bean>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 注解映射支持；JSON转换器 -->\n\t<mvc:annotation-driven>\n\t\t<mvc:message-converters register-defaults=\"true\">\n\t\t\t<bean class=\"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter\">\n\t\t\t\t<property name=\"objectMapper\" ref=\"objectMapper\" />\n\t\t\t\t<property name=\"supportedMediaTypes\">\n\t\t\t\t\t<list>\n\t\t\t\t\t\t<value>text/plain;charset=UTF-8</value>\n\t\t\t\t\t\t<value>application/json;charset=UTF-8</value>\n\t\t\t\t\t</list>\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t\t<!-- 对于字符串类型解析的配置 -->\n\t\t\t<bean class=\"org.springframework.http.converter.StringHttpMessageConverter\">  \n            \t<property name=\"supportedMediaTypes\" value = \"text/html;charset=UTF-8\" />  \n        \t</bean> \t\t\n\t\t</mvc:message-converters>\n\t</mvc:annotation-driven>\n\t\n\t<!-- freemarker的配置 -->\n\t<bean id=\"freemarkerConfig\" class=\"org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer\">\n\t\t<property name=\"templateLoaderPath\" value=\"/views/\" />\n\t\t<property name=\"defaultEncoding\" value=\"utf-8\" />\n\t\t<property name=\"freemarkerSettings\">\n\t\t\t<props>\n\t\t\t\t<prop key=\"default_encoding\">UTF-8</prop>\n\t\t\t\t<prop key=\"output_encoding\">UTF-8</prop>\n\t\t\t\t<prop key=\"template_update_delay\">10</prop>\n\t\t\t\t<prop key=\"locale\">zh_CN</prop>\n\t\t\t\t<prop key=\"datetime_format\">yyyy-MM-dd HH:mm</prop>\n\t\t\t\t<prop key=\"date_format\">yyyy-MM-dd</prop>\n\t\t\t\t<prop key=\"time_format\">HH:mm:ss</prop>\n\t\t\t\t<prop key=\"number_format\">#.##</prop>\n\t\t\t</props>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- FreeMarker视图解析 -->\n\t<bean id=\"viewResolver\" class=\"org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver\">\n\t\t<property name=\"viewClass\" value=\"org.springframework.web.servlet.view.freemarker.FreeMarkerView\"></property>\n\t\t<property name=\"suffix\" value=\".html\" />\n\t\t<property name=\"contentType\" value=\"text/html;charset=utf-8\" />\n\t\t<property name=\"exposeRequestAttributes\" value=\"true\" />\n\t\t<property name=\"exposeSessionAttributes\" value=\"true\" />\n\t\t<property name=\"exposeSpringMacroHelpers\" value=\"true\" />\n\t\t<property name=\"cache\" value=\"false\" />\n\t\t<property name=\"requestContextAttribute\" value=\"rc\"></property>\n\t</bean>\n\t\n\t<!-- 文件解析器 -->\n\t<bean id=\"multipartResolver\" class=\"org.springframework.web.multipart.commons.CommonsMultipartResolver\">\n\t\t<property name=\"maxUploadSize\" value=\"1100000\"></property>\n\t\t<property name=\"defaultEncoding\" value=\"UTF-8\"></property>\n\t</bean>\n</beans>"
  },
  {
    "path": "target/m2e-wtp/web-resources/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBuilt-By: Wxj\nBuild-Jdk: 1.8.0_181\nCreated-By: Maven Integration for Eclipse\n\n"
  },
  {
    "path": "target/m2e-wtp/web-resources/META-INF/maven/com.movie/Movie/pom.properties",
    "content": "#Generated by Maven Integration for Eclipse\n#Mon Jul 22 09:09:35 CST 2019\nversion=0.0.1-SNAPSHOT\ngroupId=com.movie\nm2e.projectName=Movie\nm2e.projectLocation=C\\:\\\\Users\\\\Wxj\\\\Desktop\\\\\\u4E1C\\u8F6F\\\\movice\\\\Movie\\\\Movie\nartifactId=Movie\n"
  },
  {
    "path": "target/m2e-wtp/web-resources/META-INF/maven/com.movie/Movie/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>com.movie</groupId>\n  <artifactId>Movie</artifactId>\n  <packaging>war</packaging>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>Movie Maven Webapp</name>\n  <url>http://maven.apache.org</url>\n  <dependencies>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>3.8.1</version>\n      <scope>test</scope>\n    </dependency>\n    \n    <!-- mysql驱动包 -->\n\t<dependency>\n\t    <groupId>mysql</groupId>\n\t    <artifactId>mysql-connector-java</artifactId>\n\t    <version>8.0.12</version>\n\t</dependency>\n\t\n    <!-- mybatis核心包 -->\n\t<dependency>\n\t    <groupId>org.mybatis</groupId>\n\t    <artifactId>mybatis</artifactId>\n\t    <version>3.4.6</version>\n\t</dependency>\n\t\n\t<!-- mybatis-spring适配器 -->\n\t<dependency>\n\t    <groupId>org.mybatis</groupId>\n\t    <artifactId>mybatis-spring</artifactId>\n\t    <version>2.0.1</version>\n\t</dependency>\n\t\n\t<!-- spring框架 --> \n\t<dependency>\n\t    <groupId>org.springframework</groupId>\n\t    <artifactId>spring-context</artifactId>\n\t    <version>5.1.6.RELEASE</version>\n\t</dependency>\n\n\t<!-- AOP支持 --> \n\t<dependency>\n\t    <groupId>org.aspectj</groupId>\n\t    <artifactId>aspectjweaver</artifactId>\n\t    <version>1.9.3</version>\n\t</dependency>\n\t\n\t<!-- spring 事务 --> \n\t<dependency>\n\t\t<groupId>org.springframework</groupId>\n\t\t<artifactId>spring-tx</artifactId>\n\t\t<version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- spring jdbc --> \n\t<dependency>\n\t\t<groupId>org.springframework</groupId>\n\t\t<artifactId>spring-jdbc</artifactId>\n\t\t<version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- 阿里巴巴连接池 -->\n    <dependency>\n\t\t<groupId>com.alibaba</groupId>\n\t\t<artifactId>druid</artifactId>\n\t\t<version>1.0.27</version>\n    </dependency>\n\n\t<!-- spring 扩展包 --> \n\t<dependency>\n\t\t<groupId>org.springframework</groupId>\n\t\t<artifactId>spring-context-support</artifactId>\n\t\t<version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- spring-webmvc框架 -->\n\t<dependency>\n\t    <groupId>org.springframework</groupId>\n\t    <artifactId>spring-webmvc</artifactId>\n\t    <version>5.1.6.RELEASE</version>\n\t</dependency>\n\t\n\t<!-- 引入jackson相关的包 -->\n\t<dependency>\n        <groupId>com.fasterxml.jackson.core</groupId>\n        <artifactId>jackson-databind</artifactId>\n        <version>2.9.3</version>\n    </dependency>\n    <dependency>\n        <groupId>com.fasterxml.jackson.core</groupId>\n        <artifactId>jackson-core</artifactId>\n        <version>2.9.3</version>\n    </dependency>\n    <dependency>\n        <groupId>com.fasterxml.jackson.core</groupId>\n        <artifactId>jackson-annotations</artifactId>\n        <version>2.9.3</version>\n    </dependency>\n    \n    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->\n\t<dependency>\n\t    <groupId>com.alibaba</groupId>\n\t    <artifactId>fastjson</artifactId>\n\t    <version>1.2.51</version>\n\t</dependency>\n    \n    <!-- https://mvnrepository.com/artifact/com.thetransactioncompany/cors-filter -->\n    <!-- 跨域 -->\n\t<dependency>\n\t    <groupId>com.thetransactioncompany</groupId>\n\t    <artifactId>cors-filter</artifactId>\n\t    <version>2.5</version>\n\t</dependency>\n    \n    <!-- 视图引擎freemarker -->\n\t<dependency>\n\t\t<groupId>org.freemarker</groupId>\n\t\t<artifactId>freemarker</artifactId>\n\t\t<version>2.3.23</version>\n\t</dependency>\n\t\n\t<!-- pagerHelp 包  mybatis分页-->\n\t <dependency>\n\t \t<groupId>com.github.pagehelper</groupId>\n\t \t<artifactId>pagehelper</artifactId> \n\t \t<version>5.1.4</version>\n\t</dependency>\n\t\n\t<!-- jstl依赖包 -->\n\t<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->\n\t<dependency>\n\t    <groupId>javax.servlet</groupId>\n\t    <artifactId>jstl</artifactId>\n\t    <version>1.2</version>\n\t</dependency>\n\t\n\t<!-- 文件上传配置 -->\n\t <dependency>\n            <groupId>commons-fileupload</groupId>\n            <artifactId>commons-fileupload</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.5</version>\n \t</dependency>\n \t\n \t<!-- 时间类型数据 -->\n \t<dependency>\n      <groupId>joda-time</groupId>\n      <artifactId>joda-time</artifactId>\n      <version>2.9.9</version>\n    </dependency>\n\n  </dependencies>\n  <build>\n    <finalName>Movie</finalName>\n    <plugins>\n    \t<plugin>\n    \t\t<groupId>org.apache.maven.plugins</groupId>\n    \t\t <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n    \t</plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "target/maven-archiver/pom.properties",
    "content": "#Generated by Maven\n#Sun Jul 21 23:12:59 CST 2019\nversion=0.0.1-SNAPSHOT\ngroupId=com.movie\nartifactId=Movie\n"
  },
  {
    "path": "target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst",
    "content": ""
  },
  {
    "path": "target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst",
    "content": "C:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\CommentServiceImp.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\IUserService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\ScheduleMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\util\\ResponseModel.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\MovieServiceImp.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\Movie.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\IHallService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\util\\test.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\Order.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\controller\\CommentController.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\controller\\MovieController.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\User.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\UserServiceImp.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\IOrderService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\OrderMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\Cinema.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\util\\UUIDUtil.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\Hall.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\ScheduleServiceImp.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\MovieMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\controller\\ScheduleController.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\OrderServiceImp.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\ICinemaService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\controller\\OrderController.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\IMovieService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\HallMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\Schedule.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\controller\\UserController.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\HallServiceImp.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\IScheduleService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\UserMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\ICommentService.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\CinemaMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\entity\\Comment.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\mapper\\CommentMapper.java\nC:\\Users\\Wxj\\Desktop\\东软\\movice\\Movie\\Movie\\src\\main\\java\\com\\service\\imp\\CinemaServiceImp.java\n"
  },
  {
    "path": "target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst",
    "content": ""
  }
]